/* src/v2/scanners.jsx — ScannersRow: insiders (live), 13F movers (live),
   AI tracker (live), IPO pipeline (live /ipo-calendar). */

const { useState: _scS, useEffect: _scE } = React;

// Fallback symbols for insider fetch when watchlist is empty
const INSIDER_FALLBACK_SYMS = ['AAPL', 'MSFT', 'NVDA', 'META', 'GOOGL', 'AMZN', 'TSLA', 'JPM'];

// Reads the watchlist directly (same key as watchlist.jsx / watchlist-sidebar.js)
function readWatchlistSyms() {
  try {
    const raw = localStorage.getItem((window.TMT_API && window.TMT_API.WATCHLIST_KEY) || 'tmt_watchlist');
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    return parsed.map(x => typeof x === 'string' ? x : (x && (x.symbol || x.sym))).filter(Boolean);
  } catch { return []; }
}

// Parse Yahoo insiderTransactions shape → our row shape
function normalizeInsiderTx(sym, tx) {
  const txt = (tx.transactionText || '').toLowerCase();
  // Yahoo's transactionText is like "Sale at price X.XX per share." or "Conversion of Exercise of derivative..."
  // Shares raw can be negative for sales on Yahoo — but often positive. Rely on transactionText + value.
  const isSell = /sale|sell|dispos/i.test(tx.transactionText || '') || /sale|sell/i.test(txt);
  const isBuy  = /purchase|buy|acquisition/i.test(tx.transactionText || '');
  const action = isBuy ? 'buy' : (isSell ? 'sell' : 'other');
  const value = (tx.value && (tx.value.raw ?? 0)) || 0;
  const shares = (tx.shares && (tx.shares.raw ?? 0)) || 0;
  const startTs = tx.startDate && tx.startDate.raw ? Number(tx.startDate.raw) * 1000 : null;
  return {
    sym,
    name: (BY_SYM[sym] && BY_SYM[sym].name) || sym,
    action,
    role: tx.filerRelation || 'Insider',
    filer: tx.filerName || '',
    shares,
    value,
    when: startTs,
  };
}

function timeAgoMs(ms) {
  if (!ms) return '—';
  const diff = Math.max(0, Date.now() - ms);
  const days = Math.floor(diff / 86400000);
  if (days < 1) return 'today';
  if (days < 7) return days + 'd ago';
  if (days < 30) return Math.floor(days / 7) + 'w ago';
  if (days < 365) return Math.floor(days / 30) + 'mo ago';
  return Math.floor(days / 365) + 'y ago';
}

// ---------- Insiders card (live — yahoo-summary per watchlist symbol) ----------
function InsidersCard() {
  const [rows, setRows] = _scS([]);
  const [loading, setLoading] = _scS(true);
  const [err, setErr] = _scS(null);

  _scE(() => {
    let alive = true;
    const wl = readWatchlistSyms();
    const syms = (wl.length > 0 ? wl : INSIDER_FALLBACK_SYMS).slice(0, 6);
    (async () => {
      const results = await Promise.allSettled(syms.map(async sym => {
        const data = await window.TMT_API.getJSON(
          '/yahoo-summary?symbol=' + encodeURIComponent(sym) + '&modules=insiderTransactions'
        );
        const result = data && data.quoteSummary && data.quoteSummary.result && data.quoteSummary.result[0];
        const tx = (result && result.insiderTransactions && result.insiderTransactions.transactions) || [];
        return tx.slice(0, 3).map(t => normalizeInsiderTx(sym, t));
      }));
      if (!alive) return;
      const all = results.flatMap(r => r.status === 'fulfilled' ? r.value : []);
      all.sort((a, b) => (b.when || 0) - (a.when || 0));
      const top = all.filter(r => r.when).slice(0, 8);
      setRows(top);
      if (top.length === 0) setErr('No recent insider activity');
      setLoading(false);
    })();
    return () => { alive = false; };
  }, []);

  return (
    <div className="card scan-card">
      <div className="card-hd">
        <span className="t">Insider filings</span>
        <a className="card-link" href="/13f.html">All filings →</a>
        <span className="explain">Recent Form 4 activity across your watchlist.</span>
      </div>
      <div className="scan-thead">
        <span>Company</span>
        <span>Insider</span>
        <span className="r">Value</span>
        <span className="r">When</span>
      </div>
      <div className="card-bd">
        {loading && <div style={{ padding: 20, color: 'var(--ink-3)', fontStyle: 'italic', fontFamily: 'var(--serif)' }}>Loading filings…</div>}
        {!loading && err && rows.length === 0 && <div style={{ padding: 20, color: 'var(--ink-3)' }}>{err}</div>}
        {rows.map((it, i) => (
          <a
            key={i}
            className="ins-row"
            href={'/details.html?symbol=' + encodeURIComponent(it.sym)}
            style={{ textDecoration: 'none' }}
          >
            <div className="who">
              <span className="sym">{it.sym}</span>
              <span className="name">{it.name}</span>
            </div>
            <div className={'act ' + (it.action === 'buy' ? 'up' : it.action === 'sell' ? 'down' : '')}>
              <span className="arrow">{it.action === 'buy' ? '▲' : it.action === 'sell' ? '▼' : '•'}</span>
              <b>{(it.role || '').slice(0, 16)}</b>
              <span className="sub">{fmtNumCompact(it.shares)}</span>
            </div>
            <span className="val">{it.value ? '$' + fmtNumCompact(it.value) : '—'}</span>
            <span className="when">{timeAgoMs(it.when)}</span>
          </a>
        ))}
      </div>
    </div>
  );
}

// ---------- AI tracker card (real /ai-tracker → arXiv papers) ----------
function fmtPaperDate(published) {
  if (!published) return '';
  const d = new Date(published);
  if (isNaN(d.getTime())) return '';
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}

function AiResearchCard() {
  const [papers, setPapers] = _scS([]);
  const [loading, setLoading] = _scS(true);
  const [err, setErr] = _scS(null);

  _scE(() => {
    let alive = true;
    (async () => {
      try {
        const data = await window.TMT_API.getJSON('/ai-tracker');
        if (!alive) return;
        // Endpoint returns { data: { papers: [{title, authors, link, summary, categories, published}], capex, capexStatements } }
        const rows = (data && data.data && data.data.papers) || [];
        setPapers(rows.slice(0, 5));
        if (rows.length === 0) setErr('No recent papers.');
      } catch (e) {
        if (alive) setErr('AI research feed is connecting — visit the full tracker for the latest papers.');
      } finally { if (alive) setLoading(false); }
    })();
    return () => { alive = false; };
  }, []);

  return (
    <div className="card scan-card">
      <div className="card-hd">
        <span className="t">AI research</span>
        <a className="card-link" href="/ai-tracker.html">Full tracker →</a>
        <span className="explain">Recent arXiv preprints across frontier ML — ranked by recency.</span>
      </div>
      <div className="card-bd">
        {loading && <div style={{ padding: 20, color: 'var(--ink-3)', fontStyle: 'italic', fontFamily: 'var(--serif)' }}>Loading papers…</div>}
        {!loading && err && papers.length === 0 && (
          <div style={{ padding: '18px 20px', color: 'var(--ink-2)', fontSize: 12.5, lineHeight: 1.5 }}>
            {err}{' '}
            <a href="/ai-tracker.html" style={{ color: 'var(--cool)', textDecoration: 'none', fontWeight: 500 }}>Open tracker →</a>
          </div>
        )}
        {papers.map((p, i) => {
          const authors = Array.isArray(p.authors) ? p.authors : [];
          const authorLine = authors.length === 0
            ? ''
            : authors.length <= 2
              ? authors.join(', ')
              : authors.slice(0, 2).join(', ') + ' +' + (authors.length - 2);
          const cat = Array.isArray(p.categories) && p.categories.length ? p.categories[0] : 'arXiv';
          const date = fmtPaperDate(p.published);
          return (
            <a
              className="ai-row"
              key={i}
              href={p.link || '#'}
              target="_blank"
              rel="noreferrer"
              style={{ textDecoration: 'none' }}
            >
              <span className="rank">{String(i + 1).padStart(2, '0')}</span>
              <div className="body">
                <span className="venue">{cat}{date ? ' · ' + date : ''}</span>
                <span className="title">{p.title || 'Untitled paper'}</span>
                <span className="auth">{authorLine}</span>
              </div>
              <div className="impact">
                <span className="score">→</span>
              </div>
            </a>
          );
        })}
      </div>
    </div>
  );
}

// ---------- IPO pipeline card (live /ipo-calendar) ----------
function fmtIpoDate(dateStr) {
  if (!dateStr) return '—';
  const d = new Date(dateStr + 'T00:00:00');
  if (isNaN(d.getTime())) return dateStr;
  return d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
}

// Map SEC filing status → our row's pill class
function ipoStatusClass(status) {
  if (!status) return 'expected';
  const s = String(status).toLowerCase();
  if (s === 'priced' || s === 'effective') return 'priced';
  if (s === 'amended') return 'roadshow';
  if (s === 'delayed' || s === 'withdrawn') return 'delayed';
  return 'expected';
}

// Extract a trading ticker from the SEC-style company string like
// "Eagle Nuclear Energy Corp.  (NUCL, NUCLW)  (CIK 0002089283)" → "NUCL"
// and return a cleaned company name (without the parenthetical suffixes).
function parseIpoCompany(raw) {
  if (!raw) return { name: '—', ticker: '' };
  const s = String(raw);
  // Find all (...) groups; last group is usually CIK, earlier one is tickers.
  const parenGroups = [...s.matchAll(/\(([^)]+)\)/g)].map(m => m[1].trim());
  let ticker = '';
  for (const g of parenGroups) {
    if (/^CIK\b/i.test(g)) continue;
    // Tickers: uppercase 1-5 chars, optional comma-sep list
    const first = g.split(',')[0].trim();
    if (/^[A-Z][A-Z0-9.\-]{0,5}$/.test(first)) { ticker = first; break; }
  }
  // Strip all parenthetical groups from the name and collapse whitespace
  const name = s.replace(/\s*\([^)]*\)\s*/g, ' ').replace(/\s{2,}/g, ' ').trim();
  return { name, ticker };
}

function IPOsCard() {
  const [filings, setFilings] = _scS([]);
  const [loading, setLoading] = _scS(true);
  const [err, setErr] = _scS(null);

  _scE(() => {
    let alive = true;
    (async () => {
      try {
        const data = await window.TMT_API.getJSON('/ipo-calendar');
        if (!alive) return;
        const payload = data && (data.data || data);
        const byWeek = (payload && payload.byWeek) || [];
        // Flatten: weeks → filings, keep week label on each row for display context
        const flat = byWeek.flatMap(w => (w.filings || []).map(f => ({ ...f, weekLabel: w.label })));
        // Sort newest first and limit
        flat.sort((a, b) => String(b.fileDate || '').localeCompare(String(a.fileDate || '')));
        setFilings(flat.slice(0, 10));
        if (flat.length === 0) setErr('No recent filings');
      } catch (e) {
        if (alive) setErr('IPO pipeline data is warming up — see the full calendar for the current S-1 and 424B filings.');
      } finally {
        if (alive) setLoading(false);
      }
    })();
    return () => { alive = false; };
  }, []);

  return (
    <div className="card scan-card">
      <div className="card-hd">
        <span className="t">IPO pipeline</span>
        <a className="card-link" href="/ipo.html">Full calendar →</a>
        <span className="explain">Recent SEC filings · S-1 and 424B prospectuses.</span>
      </div>
      <div className="scan-thead ipo">
        <span>Company</span>
        <span>Status</span>
        <span className="r">Form</span>
        <span className="r">Filed</span>
      </div>
      <div className="card-bd">
        {loading && <div style={{ padding: 20, color: 'var(--ink-3)', fontStyle: 'italic', fontFamily: 'var(--serif)' }}>Loading filings…</div>}
        {!loading && err && filings.length === 0 && (
          <div style={{ padding: '18px 20px', color: 'var(--ink-2)', fontSize: 12.5, lineHeight: 1.5 }}>
            {err}{' '}
            <a href="/ipo.html" style={{ color: 'var(--cool)', textDecoration: 'none', fontWeight: 500 }}>Open calendar →</a>
          </div>
        )}
        {filings.map((f, i) => {
          const cls = ipoStatusClass(f.status);
          const parsed = parseIpoCompany(f.company);
          const ticker = f.ticker || parsed.ticker || '';
          const hrefInternal = ticker ? ('/details.html?symbol=' + encodeURIComponent(ticker)) : null;
          const hrefExternal = !hrefInternal && f.filingUrl ? f.filingUrl : null;
          const href = hrefInternal || hrefExternal || '#';
          return (
            <a
              key={i}
              className="ipo-row"
              href={href}
              target={hrefExternal ? '_blank' : undefined}
              rel={hrefExternal ? 'noreferrer' : undefined}
              style={{ textDecoration: 'none' }}
            >
              <div className="co">
                <span className="tk">{ticker || 'Pending'}</span>
                <span className="nm">{parsed.name || f.company}</span>
              </div>
              <div className="when">
                <span className={'st ' + cls}>{(f.status || 'filed')}</span>
              </div>
              <span className="range">{f.formType || '—'}</span>
              <span className="sz">{fmtIpoDate(f.fileDate)}</span>
            </a>
          );
        })}
      </div>
    </div>
  );
}

// ---------- ScannersRow ----------
function ScannersRow() {
  return (
    <div className="scanners-row">
      <InsidersCard />
      <AiResearchCard />
      <IPOsCard />
    </div>
  );
}

Object.assign(window, { ScannersRow, InsidersCard, AiResearchCard, IPOsCard });
