// Markets tab — list of instruments grouped by category with live prices

function PriceCell({ value, digits, flash, tint, theme, align = 'right' }) {
  // flash: 'up' | 'down' | null — brief background flash on tick
  const { big, small } = splitPrice(value, digits);
  const bg = flash === 'up' ? theme.buyBg : flash === 'down' ? theme.sellBg : 'transparent';
  const color = tint === 'buy' ? theme.buy : tint === 'sell' ? theme.sell : theme.text;
  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).
    <div style={{
      textAlign: align, direction: 'ltr', unicodeBidi: 'isolate', fontVariantNumeric: 'tabular-nums',
      background: bg, borderRadius: 6, padding: '4px 6px', margin: '-4px -6px',
      transition: 'background 400ms ease',
      minWidth: 78, display: 'inline-block',
    }}>
      <span style={{ fontSize: 16, fontWeight: 600, color, letterSpacing: -0.2 }}>{big}</span>
      <span style={{ fontSize: 18, fontWeight: 700, color, letterSpacing: -0.3 }}>{small}</span>
    </div>
  );
}

function SparkLine({ data, color, width = 56, height = 20 }) {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data);
  const range = max - min || 1;
  const pts = data.map((v, i) => {
    const x = (i / (data.length - 1)) * width;
    const y = height - ((v - min) / range) * height;
    return `${x.toFixed(1)},${y.toFixed(1)}`;
  }).join(' ');
  return (
    <svg width={width} height={height} style={{ display: 'block' }}>
      <polyline points={pts} fill="none" stroke={color} strokeWidth="1.4" strokeLinejoin="round" strokeLinecap="round"/>
    </svg>
  );
}

function SymbolIcon({ sym, cat, theme }) {
  // stylized 2-letter badge, color by category
  const palette = {
    FX: ['#3B82F6', '#60A5FA'],
    Metals: ['#D97706', '#F59E0B'],
    Energy: ['#DC2626', '#F87171'],
    Indices: ['#7C3AED', '#A78BFA'],
    Crypto: ['#F7931A', '#FFB74D'],
  };
  const [a, b] = palette[cat] || ['#64748B', '#94A3B8'];
  // 2 letters: first 2 of symbol if not clearly a pair
  let label;
  if (sym.length === 6 && sym.match(/^[A-Z]{6}$/)) {
    label = sym.slice(0, 3) + '/' + sym.slice(3);
  } else {
    label = sym;
  }
  return (
    <div style={{
      width: 36, height: 36, borderRadius: 10,
      background: `linear-gradient(135deg, ${a}, ${b})`,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      flexShrink: 0, color: '#fff',
      fontSize: label.length > 5 ? 8.5 : 10, fontWeight: 700, letterSpacing: 0.2,
      boxShadow: `0 2px 8px ${a}40`,
    }}>
      {label}
    </div>
  );
}

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

function PxLive({ value, digits, pipDigits, flash, theme, align, width, size = 19 }) {
  const { base, pips, frac } = splitPip(value, digits, pipDigits);
  const bg = flash === 'up' ? theme.buyBg : flash === 'down' ? theme.sellBg : 'transparent';
  const sigSize = size;
  const baseSize = Math.round(size * 0.75);  // 75% of significant
  const fracSize = Math.round(size * 0.50);  // 50% of significant
  return (
    <div style={{ width, textAlign: align, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap', color: theme.text }}>
      {/* outer span only for the tick-flash background */}
      <span style={{
        background: bg, borderRadius: 5, padding: '2px 3px',
        transition: 'background 400ms ease',
        display: 'inline-flex', alignItems: 'flex-end', gap: 0,
        direction: 'ltr', unicodeBidi: 'isolate',
      }}>
        {/* BASE — bottom-aligned with pips (shared baseline) */}
        <span style={{ fontSize: baseSize, fontWeight: 500, lineHeight: 1, letterSpacing: 0, opacity: 0.70 }}>{base}</span>
        {/* SIGNIFICANT PIPS — visual anchor, tallest */}
        <span style={{ fontSize: sigSize, fontWeight: 700, lineHeight: 1, letterSpacing: 0 }}>{pips}</span>
        {/* FRACTIONAL — top edge flush with cap-height of pips */}
        {frac && (
          <span style={{ fontSize: fracSize, fontWeight: 600, lineHeight: 1, letterSpacing: 0, alignSelf: 'flex-start', opacity: 0.72 }}>{frac}</span>
        )}
      </span>
    </div>
  );
}

function MarketRow({ inst, state, theme, onTap, density, rowSeparator = true }) {
  const { bid, ask, flashBid, flashAsk } = state;
  const pct = inst.pctDay + (bid - inst.bid) / inst.bid * 100;
  const isUp = pct >= 0;
  const c = MKT_CAT_COLOR[inst.cat] || '#64748B';
  const pad = density === 'compact' ? '7px 16px' : density === 'spacious' ? '17px 16px' : '13px 16px';
  const sym = inst.sym.length === 6 && inst.sym.match(/^[A-Z]{6}$/)
    ? inst.sym.slice(0, 3) + '/' + inst.sym.slice(3) : inst.sym;
  const spStr = Number.isInteger(inst.spread) ? String(inst.spread) : inst.spread.toFixed(1);
  return (
    <div
      onClick={onTap}
      style={{
        display: 'flex', alignItems: 'center',
        padding: pad, cursor: 'pointer',
        borderBottom: rowSeparator ? `0.5px solid ${theme.border}` : 'none',
      }}
      onMouseDown={e => e.currentTarget.style.background = theme.bgSubtle}
      onMouseUp={e => e.currentTarget.style.background = 'transparent'}
      onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
    >
      {/* category dot */}
      <div style={{
        width: 8, height: 8, borderRadius: 4, background: c,
        boxShadow: `0 0 0 3px ${c}22`, flexShrink: 0, marginInlineEnd: 12,
      }} />
      {/* symbol + % — symbol fixed width so pct column stays pinned */}
      <div style={{ flex: 1, minWidth: 0, display: 'flex', alignItems: 'center', gap: 0 }}>
        <span style={{ fontSize: 16, fontWeight: 700, color: theme.text, letterSpacing: -0.3, minWidth: 72, flexShrink: 0 }}>{sym}</span>
        <span style={{
          display: 'inline-flex', alignItems: 'center', gap: 2,
          padding: '2px 6px', borderRadius: 6,
          background: isUp ? theme.buyBg : theme.sellBg,
          color: isUp ? theme.buy : theme.sell,
          fontSize: 11, fontWeight: 700, fontVariantNumeric: 'tabular-nums', flexShrink: 0,
        }}>
          <svg width="7" height="7" viewBox="0 0 8 8" style={{ transform: isUp ? 'none' : 'rotate(180deg)' }}>
            <path d="M4 1l3 5H1z" fill={isUp ? theme.buy : theme.sell}/>
          </svg>
          {Math.abs(pct).toFixed(2)}%
        </span>
      </div>
      {/* bid · spread · ask — fixed columns */}
      <div style={{ display: 'flex', alignItems: 'center', flexShrink: 0 }}>
        <PxLive value={bid} digits={inst.digits} pipDigits={inst.pipDigits} flash={flashBid} theme={theme} align="right" width={68} />
        <div style={{ width: 32, display: 'flex', justifyContent: 'center' }}>
          <div style={{
            fontSize: 9.5, fontWeight: 700, color: c, background: `${c}22`,
            padding: '2px 5px', borderRadius: 6, lineHeight: 1, fontVariantNumeric: 'tabular-nums',
          }}>{spStr}</div>
        </div>
        <PxLive value={ask} digits={inst.digits} pipDigits={inst.pipDigits} flash={flashAsk} theme={theme} align="left" width={68} />
      </div>
    </div>
  );
}

function CategoryChips({ active, onChange, theme }) {
  const favActive = active === 'Favorites';
  const scrollRef = React.useRef(null);
  const drag = React.useRef(null);
  const justDragged = React.useRef(false);

  // Drag-to-scroll (mouse) + stopPropagation so the tab-swipe handler
  // doesn't hijack horizontal gestures that start on the chips.
  const onDown = (e) => {
    e.stopPropagation();
    drag.current = { x: e.clientX, sl: scrollRef.current.scrollLeft, moved: false };
  };
  const onMove = (e) => {
    if (!drag.current) return;
    const dx = e.clientX - drag.current.x;
    if (Math.abs(dx) > 3) drag.current.moved = true;
    scrollRef.current.scrollLeft = drag.current.sl - dx;
  };
  const onUp = () => {
    if (drag.current && drag.current.moved) justDragged.current = true;
    drag.current = null;
  };

  return (
    <div
      ref={scrollRef}
      onMouseDown={onDown}
      onMouseMove={onMove}
      onMouseUp={onUp}
      onMouseLeave={onUp}
      onTouchStart={(e) => e.stopPropagation()}
      onClickCapture={(e) => { if (justDragged.current) { e.stopPropagation(); e.preventDefault(); justDragged.current = false; } }}
      style={{
        display: 'flex', gap: 8, padding: '4px 16px 12px',
        overflowX: 'auto', scrollbarWidth: 'none',
        touchAction: 'pan-x', WebkitOverflowScrolling: 'touch',
        cursor: 'grab', userSelect: 'none',
      }}
    >
      {/* Favorites star filter */}
      <div
        onClick={() => onChange(favActive ? 'All' : 'Favorites')}
        style={{
          width: 34, height: 34, borderRadius: 100, flexShrink: 0,
          background: favActive ? 'rgba(245,182,38,0.16)' : theme.bgElevated,
          border: favActive ? '0.5px solid rgba(245,182,38,0.45)' : `0.5px solid ${theme.border}`,
          display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer',
          transition: 'all 150ms',
        }}
      >
        <svg width="16" height="16" viewBox="0 0 24 24" fill={favActive ? '#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={favActive ? '#F5B626' : theme.textSec} strokeWidth="1.8" strokeLinejoin="round"/>
        </svg>
      </div>
      <div style={{ width: 1, alignSelf: 'stretch', background: theme.border, flexShrink: 0, margin: '3px 2px' }} />
      {['All', ...CATEGORIES].map(cat => {
        const isActive = active === cat;
        return (
          <div
            key={cat}
            onClick={() => onChange(cat)}
            style={{
              padding: '7px 14px', borderRadius: 100,
              background: isActive ? theme.text : theme.bgElevated,
              color: isActive ? theme.bg : theme.text,
              fontSize: 13, fontWeight: 600,
              whiteSpace: 'nowrap', cursor: 'pointer',
              border: isActive ? 'none' : `0.5px solid ${theme.border}`,
              letterSpacing: -0.1,
              display: 'flex', alignItems: 'center', gap: 6,
            }}
          >
            {cat !== 'All' && CAT_ICONS[cat](isActive ? theme.bg : theme.textSec)}
            {/* `cat` stays the canonical English value — it is the filter
                comparison, the CAT_ICONS key and the `inst.cat` match. Only the
                rendered label is localized. */}
            {t('common.category.' + cat.toLowerCase())}
          </div>
        );
      })}
    </div>
  );
}

// Favourites empty-state body. The ★ sits mid-sentence AND carries its own
// styling, so it is a single key with a {star} placeholder that is split at
// render time rather than substituted: a t() parameter stringifies its value,
// which would flatten the gold <span> into plain text, and three separate keys
// would nail the sentence to English word order. Only mounted when the list is
// empty, so the split allocates nothing on the per-tick path.
function FavHintBody() {
  const parts = t('markets.empty.favorites.body').split('{star}');
  return (
    <React.Fragment>
      {parts[0]}
      <span style={{ color: '#F5B626', fontWeight: 600 }}>★</span>
      {parts[1]}
    </React.Fragment>
  );
}

function MarketsTab({ prices, theme, onTap, category, setCategory, density, rowSeparator, favorites, search, setSearch, showSearch, setShowSearch }) {
  const filtered = INSTRUMENTS.filter(i => {
    if (category === 'Favorites') { if (!favorites.has(i.sym)) return false; }
    else if (category !== 'All' && i.cat !== category) return false;
    if (search && !(`${i.sym} ${i.name}`.toLowerCase().includes(search.toLowerCase()))) return false;
    return true;
  });

  // Group by category for All + Favorites; single group otherwise
  const grouped = category === 'All' || category === 'Favorites';
  const groups = React.useMemo(() => {
    if (!grouped) return [[category, filtered]];
    const out = {};
    for (const i of filtered) {
      if (!out[i.cat]) out[i.cat] = [];
      out[i.cat].push(i);
    }
    return CATEGORIES.map(c => [c, out[c] || []]).filter(([, list]) => list.length > 0);
  }, [category, filtered, grouped]);

  return (
    <div>
      {showSearch && (
        <div style={{ padding: '0 16px 10px' }}>
          <input
            autoFocus
            value={search}
            onChange={e => setSearch(e.target.value)}
            placeholder={t('markets.search.placeholder')}
            style={{
              width: '100%', padding: '10px 14px', borderRadius: 12,
              background: theme.bgElevated, border: `0.5px solid ${theme.border}`,
              color: theme.text, fontSize: 15, outline: 'none', boxSizing: 'border-box',
              fontFamily: 'inherit',
            }}
          />
        </div>
      )}

      <CategoryChips active={category} onChange={setCategory} theme={theme} />

      {/* Column header */}
      <div style={{
        display: 'flex', alignItems: 'center', padding: '0 16px 6px',
        fontSize: 10, fontWeight: 600, color: theme.textTer,
        textTransform: 'uppercase', letterSpacing: 0.6,
      }}>
        <div style={{ width: 20 }} />
        <div style={{ flex: 1 }}>{t('markets.col.symbolDay')}</div>
        <div style={{ width: 68, textAlign: 'end' }}>{t('markets.col.bid')}</div>
        <div style={{ width: 32, textAlign: 'center' }}>{t('markets.col.spread')}</div>
        <div style={{ width: 68, textAlign: 'start' }}>{t('markets.col.ask')}</div>
      </div>

      {groups.map(([cat, list]) => (
        <div key={cat}>
          {grouped && (
            <div style={{
              padding: '10px 16px 6px',
              fontSize: 12, fontWeight: 700, color: theme.textSec,
              textTransform: 'uppercase', letterSpacing: 0.6,
              display: 'flex', alignItems: 'center', gap: 6,
              background: theme.bg,
            }}>
              {CAT_ICONS[cat](theme.textSec)}
              {t('common.category.' + cat.toLowerCase())}
              <span style={{ marginInlineStart: 'auto', color: theme.textTer, fontWeight: 500 }}>
                {list.length}
              </span>
            </div>
          )}
          <div>
            {list.map(inst => (
              <MarketRow
                key={inst.sym}
                inst={inst}
                state={prices[inst.sym]}
                theme={theme}
                density={density}
                rowSeparator={rowSeparator}
                onTap={() => onTap(inst)}
              />
            ))}
          </div>
        </div>
      ))}

      {filtered.length === 0 && (
        <div style={{ padding: '50px 32px', textAlign: 'center' }}>
          {category === 'Favorites' && !search ? (
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 10 }}>
              <svg width="40" height="40" viewBox="0 0 24 24" fill="none" style={{ marginBottom: 2 }}>
                <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={theme.textTer} strokeWidth="1.6" strokeLinejoin="round"/>
              </svg>
              <div style={{ fontSize: 16, fontWeight: 600, color: theme.text }}>{t('markets.empty.favorites.title')}</div>
              <div style={{ fontSize: 13, color: theme.textSec, maxWidth: 240, lineHeight: 1.4 }}>
                <FavHintBody />
              </div>
            </div>
          ) : (
            <div style={{ color: theme.textSec }}>{t('markets.empty.noMatch', { query: search })}</div>
          )}
        </div>
      )}

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

Object.assign(window, { MarketsTab, SymbolIcon, PriceCell, SparkLine });
