// tab-accel.jsx — Flow Acceleration: per-contract vol buildup ranked vs OI
// Dollar cards: approx_premium = volume × mid × 100 (total dollars, pre-computed by server).
// Aggregation: SUM(approx_premium) per ticker. Do NOT multiply by volume or 100 again.
const { useState: useAccelState, useMemo: useAccelMemo, useEffect: useAccelEffect, useRef: useAccelRef } = React;

// ── Config ────────────────────────────────────────────────────────────────────
// DOLLAR_BASIS 'total'  → use approx_premium as-is (vol_now × mid × 100)
// DOLLAR_BASIS 'fresh'  → scale by vol_delta fraction: approx_premium × (vol_now - vol_prev) / vol_now
//   (uncomment the fresh line in buildCards and comment the total line to flip)
const DOLLAR_BASIS  = 'total';
const CARDS_MAX     = 6;         // never render more than 6 ticker cards
const COUNTUP_MS    = 700;       // animation duration

// ── Count-up card component ───────────────────────────────────────────────────
function DollarCard({ symbol, dollars, active, onClick }) {
  const [display, setDisplay] = useAccelState(0);
  const rafRef   = useAccelRef(null);
  const startRef = useAccelRef(null);

  useAccelEffect(() => {
    setDisplay(0);
    startRef.current = null;
    if (rafRef.current) cancelAnimationFrame(rafRef.current);

    function step(ts) {
      if (!startRef.current) startRef.current = ts;
      const elapsed  = ts - startRef.current;
      const progress = Math.min(elapsed / COUNTUP_MS, 1);
      const eased    = 1 - Math.pow(1 - progress, 3); // ease-out cubic
      setDisplay(Math.round(dollars * eased));
      if (progress < 1) rafRef.current = requestAnimationFrame(step);
    }
    rafRef.current = requestAnimationFrame(step);
    return () => { if (rafRef.current) cancelAnimationFrame(rafRef.current); };
  }, [dollars]);

  const borderCls = active
    ? 'border-indLite bg-cardhi'
    : 'border-line/50 bg-surface hover:border-ind/60';

  return (
    <button
      onClick={onClick}
      className={`flex flex-col items-start px-3 py-2 rounded-xl border tap transition-colors ${borderCls}`}
      style={{ minWidth: '80px' }}
    >
      <span className="font-mono text-[11px] font-bold text-white tracking-wide">{symbol}</span>
      <span className="font-mono text-xs font-extrabold prem-pop tnum leading-tight">
        {fmtPremium(display)}
      </span>
    </button>
  );
}

// ── Main tab ──────────────────────────────────────────────────────────────────
window.TabAccel = function({ accel, loading }) {
  const [filter,       setFilter]       = useAccelState('all');   // 'all' | 'call' | 'put'
  const [sortBy,       setSortBy]       = useAccelState('accel'); // 'accel' | 'ratio' | 'volume'
  const [tickerFilter, setTickerFilter] = useAccelState(null);    // symbol string or null

  // Build ticker dollar cards from the raw accel array (before type/ticker filter, after type filter)
  const tickerCards = useAccelMemo(() => {
    if (!Array.isArray(accel) || accel.length === 0) return [];

    const typeFiltered = filter === 'all' ? accel : accel.filter(r => (r.option_type || '').toLowerCase() === filter);
    const byTicker = new Map();

    for (const r of typeFiltered) {
      const prem = r.approx_premium ?? 0;
      if (!prem) continue;

      // DOLLAR_BASIS === 'total': use approx_premium directly (vol × mid × 100, server-computed)
      const dollars = prem;
      // DOLLAR_BASIS === 'fresh': scale to new volume this cycle only
      // const dollars = r.vol_prev !== null ? prem * Math.max(0, r.vol_now - r.vol_prev) / (r.vol_now || 1) : prem;

      byTicker.set(r.symbol, (byTicker.get(r.symbol) ?? 0) + dollars);
    }

    return [...byTicker.entries()]
      .map(([symbol, dollars]) => ({ symbol, dollars }))
      .sort((a, b) => b.dollars - a.dollars)
      .slice(0, CARDS_MAX);
  }, [accel, filter]);

  // Apply type + ticker filters, then sort
  const rows = useAccelMemo(() => {
    if (!Array.isArray(accel) || accel.length === 0) return [];

    const hasAccel = accel.some(r => r.accel !== null && r.accel !== undefined);

    let filtered = filter === 'all' ? accel : accel.filter(r => (r.option_type || '').toLowerCase() === filter);
    if (tickerFilter) filtered = filtered.filter(r => r.symbol === tickerFilter);

    return [...filtered].sort((a, b) => {
      if (sortBy === 'accel') {
        if (!hasAccel) return (b.ratio ?? -Infinity) - (a.ratio ?? -Infinity);
        if (a.accel !== null && b.accel === null) return -1;
        if (a.accel === null && b.accel !== null) return 1;
        if (a.accel !== null && b.accel !== null) return b.accel - a.accel;
        return (b.ratio ?? -Infinity) - (a.ratio ?? -Infinity);
      }
      if (sortBy === 'ratio')  return (b.ratio  ?? -Infinity) - (a.ratio  ?? -Infinity);
      if (sortBy === 'volume') return (b.vol_now ?? 0)         - (a.vol_now ?? 0);
      return 0;
    });
  }, [accel, filter, sortBy, tickerFilter]);

  const hasAccelValues = useAccelMemo(
    () => Array.isArray(accel) && accel.some(r => r.accel !== null && r.accel !== undefined),
    [accel]
  );

  if (loading && (!accel || accel.length === 0)) {
    return (
      <div className="space-y-2 pb-4">
        <div className="flex gap-2 mb-3">
          {Array.from({ length: 4 }).map((_, i) => (
            <div key={i} className="skel h-14 rounded-xl" style={{ minWidth: '80px' }} />
          ))}
        </div>
        {Array.from({ length: 8 }).map((_, i) => (
          <div key={i} className="skel h-12 rounded-lg" />
        ))}
      </div>
    );
  }

  function fmtAccel(v) {
    if (v === null || v === undefined) return '—';
    const sign = v >= 0 ? '+' : '';
    return `${sign}${v.toFixed(3)}x`;
  }

  function fmtRatio(v) {
    if (v === null || v === undefined) return '—';
    return `${v.toFixed(2)}x`;
  }

  function fmtExp(exp) {
    if (!exp) return '';
    return exp.slice(5).replace('-', '/');
  }

  function accelColor(v) {
    if (v === null || v === undefined) return 'text-tmuted';
    if (v >= 1.0) return 'text-green-400 font-bold';
    if (v >= 0.3) return 'text-ok font-semibold';
    if (v >= 0)   return 'text-tmuted';
    return 'text-red-400';
  }

  const SortBtn = ({ id, label }) => (
    <button
      onClick={() => setSortBy(id)}
      className={`px-2.5 py-1.5 rounded-lg text-xs font-semibold tap transition-colors ${
        sortBy === id ? 'bg-ind text-white' : 'bg-surface text-tmuted border border-line'
      }`}
    >
      {label}
    </button>
  );

  return (
    <div className="pb-4">
      <AIObserver tab="flow" />

      {/* Dollar accumulation ticker cards */}
      {tickerCards.length > 0 && (
        <div className="flex gap-2 mb-3 overflow-x-auto scroll-x pb-1">
          {tickerCards.map(card => (
            <DollarCard
              key={card.symbol}
              symbol={card.symbol}
              dollars={card.dollars}
              active={tickerFilter === card.symbol}
              onClick={() => setTickerFilter(f => f === card.symbol ? null : card.symbol)}
            />
          ))}
        </div>
      )}

      {/* Status line */}
      {!hasAccelValues && accel.length > 0 && (
        <div className="flex items-center gap-1.5 text-[11px] text-tmuted font-mono mb-2 px-0.5">
          <span className="w-1.5 h-1.5 rounded-full bg-amber-500 shrink-0" />
          Waiting for 2nd cycle — showing Vol/OI rank
        </div>
      )}
      {hasAccelValues && (
        <div className="flex items-center gap-1.5 text-[11px] text-tmuted font-mono mb-2 px-0.5">
          <span className="w-1.5 h-1.5 rounded-full bg-ok shrink-0" />
          Live acceleration — (vol₂ − vol₁) ÷ OI
          {tickerFilter && (
            <button onClick={() => setTickerFilter(null)}
              className="ml-auto text-[10px] text-indLite tap underline">
              {tickerFilter} ✕ clear
            </button>
          )}
        </div>
      )}
      {!hasAccelValues && accel.length > 0 && tickerFilter && (
        <div className="flex justify-end mb-1">
          <button onClick={() => setTickerFilter(null)}
            className="text-[10px] text-indLite tap underline">
            {tickerFilter} ✕ clear
          </button>
        </div>
      )}

      {/* Filter + sort bar */}
      <div className="flex gap-2 mb-3 flex-wrap">
        {['all', 'call', 'put'].map(f => (
          <button key={f} onClick={() => { setFilter(f); setTickerFilter(null); }}
            className={`px-3 py-1.5 rounded-lg text-xs font-semibold uppercase tap transition-colors ${
              filter === f ? 'bg-ind text-white' : 'bg-surface text-tmuted border border-line'
            }`}>
            {f}
          </button>
        ))}
        <div className="flex-1" />
        <SortBtn id="accel"  label="Accel" />
        <SortBtn id="ratio"  label="Vol/OI" />
        <SortBtn id="volume" label="Volume" />
      </div>

      {rows.length === 0 && (
        <Card>
          <EmptyMsg msg={
            accel.length === 0 ? 'Waiting for first writer cycle'
            : tickerFilter      ? `No ${tickerFilter} contracts match filters`
            : 'No contracts match filters'
          } />
        </Card>
      )}

      {rows.length > 0 && (
        <div className="text-[10px] text-tmuted mb-2">
          {rows.length} contracts{tickerFilter ? ` · ${tickerFilter}` : ''}
        </div>
      )}

      <div className="space-y-1.5">
        {rows.map((row, i) => {
          const type    = (row.option_type || '').toUpperCase();
          const typeClr = type === 'CALL' ? 'text-green-400' : 'text-red-400';
          const { text: spottedText, dotCls } = fmtSpottedTime(row.scanned_at);
          const isNew   = row.source === 'new';

          return (
            <Card key={row.contract_symbol || i}>
              <div className="px-3 py-2">
                <div className="flex items-center gap-2">
                  <button
                    onClick={() => setTickerFilter(f => f === row.symbol ? null : row.symbol)}
                    className="font-mono text-xs font-bold text-white shrink-0 tap"
                  >
                    {row.symbol}
                  </button>
                  <span className={`font-mono text-xs font-bold shrink-0 ${typeClr}`}>
                    ${row.strike}
                  </span>
                  <span className="text-tmuted text-[10px] shrink-0">
                    {fmtExp(row.expiration_date)} {type[0]}
                  </span>
                  <TierBadge tier={row.tier} />
                  {isNew && (
                    <span className="text-[9px] font-mono text-amber-400 shrink-0">new</span>
                  )}
                  <div className="flex-1" />
                  <span className={`font-mono text-xs shrink-0 ${accelColor(row.accel)}`}>
                    {fmtAccel(row.accel)}
                  </span>
                </div>
                <div className="flex items-center gap-3 mt-0.5 text-[10px] text-tmuted font-mono flex-wrap">
                  <span>Vol <span className="text-white">{fmtVol(row.vol_now)}</span></span>
                  {row.vol_prev !== null && row.vol_prev !== undefined && (
                    <span>prev <span className="text-white">{fmtVol(row.vol_prev)}</span></span>
                  )}
                  <span>OI <span className="text-white">{fmtVol(row.oi_now)}</span></span>
                  {row.ratio !== null && row.ratio !== undefined && (
                    <span className={row.ratio >= 1 ? 'text-ok font-semibold' : ''}>
                      {fmtRatio(row.ratio)} vol/OI
                    </span>
                  )}
                  {row.approx_premium > 0 && (
                    <span className="text-indLite font-semibold">{fmtPremium(row.approx_premium)}</span>
                  )}
                  {spottedText && (
                    <span className="flex items-center gap-1 ml-auto">
                      <span className={`w-1.5 h-1.5 rounded-full shrink-0 ${dotCls}`} />
                      <span>{spottedText}</span>
                    </span>
                  )}
                </div>
              </div>
            </Card>
          );
        })}
      </div>
    </div>
  );
};
