// Live instrument detail screen — variant #3 (dual hero + dual-column depth)
// Tabs: Depth · Chart (candles) · Spec. Fixed SELL/BUY across all tabs.

// 3-part price (base · significant pips · fractional), top-of-book sized
function DPxLive({ value, inst, size = 30, color, weight = 700 }) {
  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', gap: 0, direction: 'ltr', unicodeBidi: 'isolate', color, fontVariantNumeric: 'tabular-nums', lineHeight: 1 }}>
      <span style={{ fontSize: Math.round(size * 0.75), fontWeight: weight, lineHeight: 1, opacity: 0.72 }}>{base}</span>
      <span style={{ fontSize: size, fontWeight: weight, lineHeight: 1 }}>{pips}</span>
      {frac && <span style={{ fontSize: Math.round(size * 0.50), fontWeight: weight, lineHeight: 1, alignSelf: 'flex-start', opacity: 0.74 }}>{frac}</span>}
    </span>
  );
}

const DET_CAT_COLOR = { FX: '#3B82F6', Metals: '#E0A21A', Energy: '#E2563B', Indices: '#8B5CF6', Crypto: '#F7931A' };

function detVol(v) { return v.toFixed(2); }

const CHART_TFS = ['1m', '5m', '15m', '1H', '4H', '1D'];

// Timeframe codes are the values the chart, the candle request and the cell
// state all compare against — they stay canonical. Only the chip's LABEL is
// localized, looked up at render time (a t() call out here would run before
// initI18n() resolves). MT platforms localize these, so the regional teams get
// the choice; the en values are the codes themselves.
const TF_LABEL_KEY = {
  '1m': 'chart.tf.m1', '5m': 'chart.tf.m5', '15m': 'chart.tf.m15',
  '1H': 'chart.tf.h1', '4H': 'chart.tf.h4', '1D': 'chart.tf.d1',
};

// Real OHLC from the candle store (ts_candles via /api/instruments/candles);
// 1m aggregated live from the base feed, higher TFs rolled up server-side.
function CandleChart({ inst, ps, theme }) {
  const [tf, setTf] = React.useState('1m');
  const [candles, setCandles] = React.useState(null); // null = loading
  React.useEffect(() => {
    let alive = true;
    const load = () => apiCandles(inst, tf, 60)
      .then(res => { if (alive) setCandles(res.candles || []); })
      .catch(() => { if (alive) setCandles([]); });
    setCandles(null);
    load();
    const id = setInterval(load, 5000); // forming candle updates live
    return () => { alive = false; clearInterval(id); };
  }, [inst.sym, tf]);

  const tfBar = (
    <div style={{ display: 'flex', justifyContent: 'space-around', marginTop: 12 }}>
      {CHART_TFS.map(code => (
        <div key={code} onClick={() => setTf(code)} style={{ padding: '6px 12px', borderRadius: 8, fontSize: 12.5, fontWeight: 600, color: code === tf ? theme.text : theme.textSec, background: code === tf ? theme.bgCard : 'transparent', cursor: 'pointer' }}>{t(TF_LABEL_KEY[code])}</div>
      ))}
    </div>
  );
  if (!candles || candles.length < 2) {
    return (
      <div style={{ padding: '10px 16px 0' }}>
        <div style={{ height: 232, display: 'flex', alignItems: 'center', justifyContent: 'center', color: theme.textTer, fontSize: 12.5 }}>
          {candles === null ? t('chart.loading') : t('chart.collectingHint')}
        </div>
        {tfBar}
      </div>
    );
  }
  const W = 372, H = 232, padR = 52;
  const plotW = W - padR;
  const his = candles.map(c => c.h), los = candles.map(c => c.l);
  const max = Math.max(...his), min = Math.min(...los), rng = (max - min) || 1;
  const y = (v) => H - ((v - min) / rng) * (H - 20) - 10;
  const slot = plotW / candles.length;
  const bodyW = slot * 0.62;
  const last = candles[candles.length - 1];
  const lastUp = last.c >= last.o;
  const lastY = y(ps.bid);
  return (
    <div style={{ padding: '10px 16px 0' }}>
      <svg width="100%" viewBox={`0 0 ${W} ${H}`} style={{ display: 'block', overflow: 'visible' }}>
        {/* gridlines + right axis labels */}
        {[0, 0.25, 0.5, 0.75, 1].map(f => {
          const v = max - f * rng; const yy = y(v);
          return (
            <g key={f}>
              <line x1="0" y1={yy} x2={plotW} y2={yy} stroke={theme.border} strokeWidth="0.5"/>
              <text x={W} y={yy + 3} textAnchor="end" fontSize="9.5" fill={theme.textTer} fontFamily="-apple-system, system-ui" style={{ fontVariantNumeric: 'tabular-nums' }}>{fmtPrice(v, inst.digits)}</text>
            </g>
          );
        })}
        {/* candles */}
        {candles.map((cd, i) => {
          const cx = i * slot + slot / 2;
          const up = cd.c >= cd.o;
          const col = up ? theme.buy : theme.sell;
          const bodyTop = y(Math.max(cd.o, cd.c));
          const bodyBot = y(Math.min(cd.o, cd.c));
          return (
            <g key={i}>
              <line x1={cx} y1={y(cd.h)} x2={cx} y2={y(cd.l)} stroke={col} strokeWidth="1"/>
              <rect x={cx - bodyW / 2} y={bodyTop} width={bodyW} height={Math.max(1, bodyBot - bodyTop)} fill={col} rx="0.5"/>
            </g>
          );
        })}
        {/* current price line */}
        <line x1="0" y1={lastY} x2={plotW} y2={lastY} stroke={lastUp ? theme.buy : theme.sell} strokeWidth="1" strokeDasharray="3 3" opacity="0.7"/>
        <rect x={plotW} y={lastY - 8} width={padR} height="16" fill={lastUp ? theme.buy : theme.sell} rx="3"/>
        <text x={W - 4} y={lastY + 3.5} textAnchor="end" fontSize="10" fontWeight="700" fill="#fff" fontFamily="-apple-system, system-ui" style={{ fontVariantNumeric: 'tabular-nums' }}>{fmtPrice(ps.bid, inst.digits)}</text>
      </svg>
      {tfBar}
    </div>
  );
}

// Real order-book depth: the monolith's book mirror via /api/instruments/
// depth, marked with the account group's markup. Polled while the tab is open.
function DepthCols({ inst, ps, theme }) {
  const [book, setBook] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    const load = () => apiDepth(inst)
      .then(res => { if (alive) setBook(res); })
      .catch(() => { if (alive) setBook({ bids: [], asks: [] }); });
    load();
    const id = setInterval(load, 2000);
    return () => { alive = false; clearInterval(id); };
  }, [inst.sym]);
  if (!book || (!book.bids.length && !book.asks.length)) {
    return (
      <div style={{ height: 180, display: 'flex', alignItems: 'center', justifyContent: 'center', color: theme.textTer, fontSize: 12.5 }}>
        {book === null ? t('book.loading') : t('book.noDepth')}
      </div>
    );
  }
  const bids = book.bids, asks = book.asks;
  const max = Math.max(...bids.map(l => l.vol), ...asks.map(l => l.vol), 0.01);
  const buyBar = theme.buy + '33', sellBar = theme.sell + '33';
  const col = (lvl, isAsk) => {
    const w = (lvl.vol / max) * 100;
    const c = isAsk ? theme.sell : theme.buy;
    const bar = isAsk ? sellBar : buyBar;
    return (
      // Physical left/right throughout, deliberately: the ladder is pinned LTR
      // by the dir="ltr" wrapper below, so "left" and "right" mean what they
      // say here and logical properties would flip back out of the pin.
      <div key={lvl.price} style={{ position: 'relative', display: 'flex', alignItems: 'center', height: 33, padding: '0 12px', fontSize: 12.5, fontVariantNumeric: 'tabular-nums' }}>
        <div style={{ position: 'absolute', top: 3, bottom: 3, [isAsk ? 'left' : 'right']: 0, width: `${w}%`, background: bar, borderRadius: isAsk ? '0 4px 4px 0' : '4px 0 0 4px' }}/>
        {isAsk ? (
          <>
            <span style={{ position: 'relative', color: c, fontWeight: 700, minWidth: 58 }}>{fmtPrice(lvl.price, inst.digits)}</span>
            <span style={{ position: 'relative', color: theme.textSec, fontWeight: 600, marginLeft: 'auto' }}>{detVol(lvl.vol)}</span>
          </>
        ) : (
          <>
            <span style={{ position: 'relative', color: theme.textSec, fontWeight: 600, marginRight: 'auto' }}>{detVol(lvl.vol)}</span>
            <span style={{ position: 'relative', color: c, fontWeight: 700, minWidth: 58, textAlign: 'right' }}>{fmtPrice(lvl.price, inst.digits)}</span>
          </>
        )}
      </div>
    );
  };
  return (
    // ——— the depth ladder does NOT mirror (docs/i18n.md ID5/IO3) ———
    // Bids on the left growing right, asks on the right growing left, prices
    // meeting at the spread: one shape every desk reads the same way, and the
    // bars are a spatial encoding of size rather than decoration. Mirroring
    // would swap the two sides and flip every bar away from its price. Pinned
    // LTR here so the whole subtree keeps physical geometry; the Arabic column
    // headers still shape right-to-left inside their own cells, because
    // Arabic is strong-RTL within its own run.
    <div dir="ltr" style={{ padding: '8px 0' }}>
      <div style={{ display: 'flex' }}>
        <div style={{ flex: 1, fontSize: 9.5, fontWeight: 700, color: theme.buy, textTransform: 'uppercase', letterSpacing: 0.6, padding: '2px 12px 8px' }}>{t('book.col.bids')}</div>
        <div style={{ width: 1, background: theme.border }}/>
        <div style={{ flex: 1, fontSize: 9.5, fontWeight: 700, color: theme.sell, textTransform: 'uppercase', letterSpacing: 0.6, padding: '2px 12px 8px', textAlign: 'right' }}>{t('book.col.asks')}</div>
      </div>
      <div style={{ display: 'flex' }}>
        <div style={{ flex: 1 }}>{bids.map(l => col(l, false))}</div>
        <div style={{ width: 1, background: theme.border }}/>
        <div style={{ flex: 1 }}>{asks.map(l => col(l, true))}</div>
      </div>
    </div>
  );
}

// Real contract specification (M6): instrument master + account leverage +
// group swap points from the Backoffice. Absent values render as an em dash —
// nothing is invented.
function SpecSheet({ inst, theme }) {
  const [spec, setSpec] = React.useState(null);
  React.useEffect(() => {
    let alive = true;
    apiSpec(inst).then(s => { if (alive) setSpec(s); }).catch(() => { if (alive) setSpec({}); });
    return () => { alive = false; };
  }, [inst.sym]);
  if (spec === null) {
    return <div style={{ height: 180, display: 'flex', alignItems: 'center', justifyContent: 'center', color: theme.textTer, fontSize: 12.5 }}>{t('spec.loading')}</div>;
  }
  const dash = '—';
  const base = inst.backend.includes('/') ? inst.backend.split('/')[0] : inst.sym;
  const contract = spec.contractSize ? spec.contractSize.toLocaleString('en-US') + ' ' + base : dash;
  const marginCalc = spec.marginStrategy === 'without-leverage' ? t('spec.marginCalc.fullNotionalNoLeverage') : t('spec.marginCalc.accountLeverage');
  const leverage = spec.leverage ? '1:' + spec.leverage : dash;
  const marginPct = spec.marginPct ? (parseFloat(spec.marginPct) * 100).toFixed(0) + '%' : dash;
  // The L/S swap legs are one key each rather than a translated letter glued to
  // a number — the letter and the value have to stay one phrase to reorder.
  const swaps = (spec.swapLong != null || spec.swapShort != null)
    ? <span style={{ display: 'flex', gap: 14 }}>
        <span style={{ color: theme.sell }}>{t('spec.swap.long', { value: spec.swapLong != null ? spec.swapLong : dash })}</span>
        <span style={{ color: theme.buy }}>{t('spec.swap.short', { value: spec.swapShort != null ? spec.swapShort : dash })}</span>
      </span>
    : dash;
  const rows = [
    [t('spec.marginCalc.label'), marginCalc],
    [t('spec.accountLeverage'), leverage],
    [t('spec.marginPct'), marginPct],
    [t('spec.contractSizeLot'), contract],
    [t('spec.pointSize'), spec.tickSize ? spec.tickSize.toFixed(inst.digits) : dash],
    // Three numbers joined by neutral separators, and the ORDER carries the
    // whole meaning — min, step, max. Un-isolated under RTL the separators
    // resolve RTL (UBA N1: a number acts as R for the neutrals beside it) and
    // the run reverses to "100.00 / 0.01 / 0.01" — min and max swapped. The
    // value cell cannot be pinned LTR instead: other rows in the same column
    // hold translated words. Same class as the chart grid picker's "R×C".
    [t('spec.minStepMaxLots'), spec.minVol
      ? bidiIsolate(`${spec.minVol.toFixed(2)} / ${spec.volStep.toFixed(2)} / ${spec.maxVol.toFixed(2)}`)
      : dash],
    [t('spec.swapRatesPoints'), swaps],
    [t('spec.group'), spec.group || dash],
    [t('spec.tradingSession.label'), t('spec.tradingSession.value')],
  ];
  return (
    <div style={{ padding: '12px 16px' }}>
      <div style={{ fontSize: 11, fontWeight: 700, color: theme.textTer, textTransform: 'uppercase', letterSpacing: 0.7, padding: '0 4px 8px' }}>{t('spec.title')}</div>
      <div style={{ background: theme.bgCard, borderRadius: 16, border: `0.5px solid ${theme.border}`, overflow: 'hidden' }}>
        {rows.map(([label, value], i) => (
          <div key={label} style={{ display: 'flex', alignItems: 'center', minHeight: 46, padding: '9px 16px', borderBottom: i < rows.length - 1 ? `0.5px solid ${theme.border}` : 'none', gap: 12 }}>
            <div style={{ fontSize: 13.5, color: theme.textSec, flex: 1 }}>{label}</div>
            <div style={{ fontSize: 14, fontWeight: 600, color: theme.text, fontVariantNumeric: 'tabular-nums', textAlign: 'end' }}>{value}</div>
          </div>
        ))}
      </div>
      <div style={{ fontSize: 11, color: theme.textTer, padding: '10px 4px', lineHeight: 1.5 }}>
        {t('spec.footer.short')}
      </div>
    </div>
  );
}

function InstrumentDetail({ inst, priceState, theme, onClose, onBuy, onSell, isFav, onToggleFav }) {
  const [tab, setTab] = React.useState('Chart');
  const [entered, setEntered] = React.useState(false);
  React.useEffect(() => { const r = requestAnimationFrame(() => setEntered(true)); return () => cancelAnimationFrame(r); }, []);
  const ps = priceState;
  const pct = inst.pctDay; // live: api.jsx recomputes vs dayOpen on every tick
  const up = pct >= 0;
  const c = DET_CAT_COLOR[inst.cat] || theme.accent;

  return (
    <div style={{
      position: 'absolute', inset: 0, zIndex: 90, background: theme.bg,
      // The detail screen slides in from the FORWARD edge — the side a "next"
      // gesture comes from. That is the right under LTR and the left under
      // RTL, so the offscreen offset flips with direction; leaving it at
      // +100% would have Arabic screens arriving from behind the back button.
      transform: entered ? 'translateX(0)' : `translateX(${i18nIsRTL() ? '-100%' : '100%'})`,
      transition: 'transform 280ms cubic-bezier(0.2, 0.8, 0.3, 1)',
      display: 'flex', flexDirection: 'column',
    }}>
      {/* Top bar */}
      <div style={{ padding: '52px 16px 10px', display: 'flex', alignItems: 'center', gap: 10 }}>
        <div onClick={onClose} style={{ width: 34, height: 34, borderRadius: 17, background: theme.bgElevated, border: `0.5px solid ${theme.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none"><path d="M15 18l-6-6 6-6" stroke={theme.text} strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/></svg>
        </div>
        <div style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ width: 7, height: 7, borderRadius: 4, background: c, boxShadow: `0 0 0 3px ${c}22` }}/>
          <div>
            <div style={{ fontSize: 16, fontWeight: 700, color: theme.text, letterSpacing: -0.3, lineHeight: '17px' }}>
              {inst.sym.length === 6 && inst.sym.match(/^[A-Z]{6}$/) ? inst.sym.slice(0, 3) + '/' + inst.sym.slice(3) : inst.sym}
            </div>
            <div style={{ fontSize: 10.5, color: theme.textSec, lineHeight: '13px' }}>{inst.name}</div>
          </div>
        </div>
        <div onClick={onToggleFav} style={{ width: 34, height: 34, borderRadius: 17, background: isFav ? 'rgba(245,182,38,0.14)' : theme.bgElevated, border: isFav ? '0.5px solid rgba(245,182,38,0.35)' : `0.5px solid ${theme.border}`, display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer' }}>
          <svg width="15" height="15" viewBox="0 0 24 24" fill={isFav ? '#F5B626' : 'none'}><path d="M12 2l2.4 7.4H22l-6.2 4.5 2.4 7.4L12 16.8l-6.2 4.5 2.4-7.4L2 9.4h7.6z" stroke={isFav ? '#F5B626' : theme.textSec} strokeWidth="1.6" strokeLinejoin="round"/></svg>
        </div>
      </div>

      {/* Hero — dual BID/ASK blocks + spread + stats */}
      <div style={{ padding: '10px 16px 12px' }}>
        <div style={{ display: 'flex', alignItems: 'stretch', borderRadius: 16, overflow: 'hidden', border: `0.5px solid ${theme.border}` }}>
          <div style={{ flex: 1, background: theme.sellBg, padding: '12px 14px' }}>
            <div style={{ fontSize: 10.5, fontWeight: 700, color: theme.sell, textTransform: 'uppercase', letterSpacing: 0.6 }}>{t('detail.hero.bidSell')}</div>
            <div style={{ marginTop: 5 }}><DPxLive value={ps.bid} inst={inst} size={30} color={theme.text}/></div>
          </div>
          <div style={{ width: 1, background: theme.border, position: 'relative' }}>
            <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%,-50%)', background: theme.bgCard, border: `0.5px solid ${theme.borderStrong}`, borderRadius: 8, padding: '3px 7px', fontSize: 11, fontWeight: 700, color: theme.textSec, whiteSpace: 'nowrap' }}>{inst.spread.toFixed(1)}</div>
          </div>
          <div style={{ flex: 1, background: theme.buyBg, padding: '12px 14px', textAlign: 'end' }}>
            <div style={{ fontSize: 10.5, fontWeight: 700, color: theme.buy, textTransform: 'uppercase', letterSpacing: 0.6 }}>{t('detail.hero.askBuy')}</div>
            <div style={{ marginTop: 5 }}><DPxLive value={ps.ask} inst={inst} size={30} color={theme.text}/></div>
          </div>
        </div>
        <div style={{ display: 'flex', gap: 20, marginTop: 10, padding: '0 2px' }}>
          <DetStat label={t('detail.stat.today')} value={bidiIsolate((up ? '+' : '') + pct.toFixed(2) + '%')} color={up ? theme.buy : theme.sell} theme={theme}/>
          <DetStat label={t('detail.stat.high')} value={inst.dayHigh > 0 ? fmtPrice(inst.dayHigh, inst.digits) : '—'} theme={theme}/>
          <DetStat label={t('detail.stat.low')} value={inst.dayLow > 0 ? fmtPrice(inst.dayLow, inst.digits) : '—'} theme={theme}/>
        </div>
      </div>

      {/* Tabs */}
      <div style={{ display: 'flex', gap: 4, padding: '0 16px', borderBottom: `0.5px solid ${theme.border}` }}>
        {/* The first element stays the canonical English tab id — it is the
            `tab` state and every branch below compares against it. Only the
            second, the label, is localized. (The map parameter can no longer be
            named `t`: that is the i18n function.) */}
        {[['Chart', 'detail.tab.chart'], ['Depth', 'detail.tab.depth'], ['Spec', 'detail.tab.spec']].map(([v, key]) => (
          <div key={v} onClick={() => setTab(v)} style={{ flex: 1, textAlign: 'center', padding: '11px 0 12px', fontSize: 13.5, fontWeight: 600, color: v === tab ? theme.text : theme.textSec, position: 'relative', cursor: 'pointer' }}>
            {t(key)}
            {v === tab && <div style={{ position: 'absolute', bottom: -0.5, left: '50%', transform: 'translateX(-50%)', width: 30, height: 2.5, borderRadius: 2, background: theme.text }}/>}
          </div>
        ))}
      </div>

      {/* Tab content */}
      <div style={{ flex: 1, overflowY: 'auto' }}>
        {tab === 'Depth' && <DepthCols inst={inst} ps={ps} theme={theme}/>}
        {tab === 'Chart' && <CandleChart inst={inst} ps={ps} theme={theme}/>}
        {tab === 'Spec' && <SpecSheet inst={inst} theme={theme}/>}
      </div>

      {/* Fixed SELL / BUY */}
      <div style={{ display: 'flex', gap: 10, padding: '12px 16px 34px', background: theme.bg, borderTop: `0.5px solid ${theme.border}` }}>
        <div onClick={onSell} style={{ flex: 1, padding: '13px 14px', borderRadius: 14, background: theme.sell, display: 'flex', flexDirection: 'column', alignItems: 'center', cursor: 'pointer', boxShadow: `0 6px 16px ${theme.sell}44` }}>
          <span style={{ fontSize: 11, fontWeight: 700, color: 'rgba(255,255,255,0.85)', textTransform: 'uppercase', letterSpacing: 0.6 }}>{t('common.side.sell')}</span>
          <span style={{ marginTop: 2 }}><DPxLive value={ps.bid} inst={inst} size={20} color="#fff"/></span>
        </div>
        <div onClick={onBuy} style={{ flex: 1, padding: '13px 14px', borderRadius: 14, background: theme.buy, display: 'flex', flexDirection: 'column', alignItems: 'center', cursor: 'pointer', boxShadow: `0 6px 16px ${theme.buy}44` }}>
          <span style={{ fontSize: 11, fontWeight: 700, color: 'rgba(255,255,255,0.9)', textTransform: 'uppercase', letterSpacing: 0.6 }}>{t('common.side.buy')}</span>
          <span style={{ marginTop: 2 }}><DPxLive value={ps.ask} inst={inst} size={20} color="#fff"/></span>
        </div>
      </div>
    </div>
  );
}

function DetStat({ label, value, color, theme }) {
  return (
    <div>
      <div style={{ fontSize: 9.5, fontWeight: 600, color: theme.textTer, textTransform: 'uppercase', letterSpacing: 0.5 }}>{label}</div>
      <div style={{ fontSize: 13, fontWeight: 600, color: color || theme.text, fontVariantNumeric: 'tabular-nums', marginTop: 2 }}>{value}</div>
    </div>
  );
}

Object.assign(window, { InstrumentDetail });
