/* v3/activity.jsx — watchlist-driven activity feed.
   Sources (all filtered to user's watchlist symbols):
     - Triggered price alerts from localStorage['tmt_price_alerts']
     - Upcoming earnings (next 14d) from /asset-details.earningsDate
     - Recent company news from /asset-details.news (Yahoo Finance) */
const { useState: useAC_S, useEffect: useAC_E, useCallback: useAC_C } = React;

const WL_KEY_ACT = (window.TMT_API && window.TMT_API.WATCHLIST_KEY) || 'tmt_watchlist';
const ALERTS_KEY_ACT = 'tmt_price_alerts';
const SYMBOL_FETCH_CAP = 10;
const REFRESH_MS = 5 * 60 * 1000;

const KIND_META = {
  alert: { dot: "var(--warm)",  label: "ALERT" },
  earn:  { dot: "var(--cool)",  label: "EARN"  },
  news:  { dot: "var(--ink-2)", label: "NEWS"  },
};

function readWatchlistSyms() {
  try {
    const raw = localStorage.getItem(WL_KEY_ACT);
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    return parsed
      .map(it => typeof it === 'string' ? it : (it && (it.symbol || it.sym)))
      .filter(Boolean)
      .map(s => String(s).toUpperCase());
  } catch { return []; }
}

function readTriggeredAlerts(watchlist) {
  try {
    const raw = localStorage.getItem(ALERTS_KEY_ACT);
    if (!raw) return [];
    const parsed = JSON.parse(raw);
    if (!Array.isArray(parsed)) return [];
    const wlSet = new Set(watchlist);
    return parsed
      .filter(a => a && a.triggered && a.triggeredAt && wlSet.has(String(a.symbol).toUpperCase()))
      .map(a => {
        const direction = a.condition === 'above' ? 'crossed above' : 'dropped below';
        const triggeredPx = typeof a.triggeredPrice === 'number' ? `$${a.triggeredPrice.toFixed(2)}` : '';
        return {
          id: `alert-${a.id}`,
          kind: 'alert',
          sym: String(a.symbol).toUpperCase(),
          text: `Price alert · ${direction} $${Number(a.targetPrice).toFixed(2)}${triggeredPx ? ' · now ' + triggeredPx : ''}`,
          meta: a.condition === 'above' ? 'above target' : 'below target',
          ts: a.triggeredAt,
          href: `/details.html?symbol=${encodeURIComponent(a.symbol)}`,
        };
      });
  } catch { return []; }
}

function timeAgoSec(s) {
  if (s < 60) return s + "s";
  if (s < 3600) return Math.floor(s / 60) + "m";
  if (s < 86400) return Math.floor(s / 3600) + "h";
  return Math.floor(s / 86400) + "d";
}

function fmtRelative(ts, now) {
  const diff = Math.max(0, Math.floor((now - ts) / 1000));
  return diff === 0 ? 'just now' : timeAgoSec(diff) + ' ago';
}

function fmtUntil(ts, now) {
  const days = Math.floor((ts - now) / 86400000);
  if (days <= 0) return 'today';
  if (days === 1) return 'tomorrow';
  return `in ${days}d`;
}

async function fetchAssetDetailsForSyms(syms) {
  if (!window.TMT_API || typeof window.TMT_API.getJSON !== 'function') return [];
  const results = await Promise.allSettled(
    syms.map(s => window.TMT_API.getJSON('/asset-details?symbol=' + encodeURIComponent(s)))
  );
  return results.map((r, i) => ({ sym: syms[i], r }));
}

function extractEarningsItem(sym, data, now) {
  if (!data || !data.earningsDate) return null;
  const ed = new Date(data.earningsDate).getTime();
  if (!Number.isFinite(ed)) return null;
  const days = Math.floor((ed - now) / 86400000);
  if (days < 0 || days > 14) return null;
  return {
    id: `earn-${sym}-${ed}`,
    kind: 'earn',
    sym,
    text: `Reports earnings ${fmtUntil(ed, now)}`,
    meta: 'upcoming',
    ts: now, // float to top of feed within the earn category
    href: `/details.html?symbol=${encodeURIComponent(sym)}`,
  };
}

function extractNewsItems(sym, data, perSymbolCap) {
  const news = Array.isArray(data && data.news) ? data.news : [];
  const out = [];
  for (const n of news) {
    if (!n || !n.title) continue;
    const ts = n.publishedAt ? new Date(n.publishedAt).getTime() : 0;
    if (!Number.isFinite(ts) || ts <= 0) continue;
    out.push({
      id: `news-${sym}-${n.link || n.title}`,
      kind: 'news',
      sym,
      text: `${n.publisher || 'News'}: ${n.title}`,
      meta: 'headline',
      ts,
      href: n.link || `/details.html?symbol=${encodeURIComponent(sym)}`,
    });
    if (out.length >= perSymbolCap) break;
  }
  return out;
}

function ActivityFeed() {
  const [items, setItems] = useAC_S([]);
  const [status, setStatus] = useAC_S('loading'); // 'loading' | 'empty' | 'ready' | 'error'
  const [, setTick] = useAC_S(0);

  const load = useAC_C(async () => {
    const watchlist = readWatchlistSyms();
    if (watchlist.length === 0) {
      setItems([]);
      setStatus('empty');
      return;
    }

    const now = Date.now();
    const all = [];

    all.push(...readTriggeredAlerts(watchlist));

    const symsToFetch = watchlist.slice(0, SYMBOL_FETCH_CAP);
    let fetched = [];
    try {
      fetched = await fetchAssetDetailsForSyms(symsToFetch);
    } catch {
      fetched = [];
    }

    fetched.forEach(({ sym, r }) => {
      if (r.status !== 'fulfilled' || !r.value || r.value.success === false) return;
      const data = r.value.data || {};
      const earn = extractEarningsItem(sym, data, now);
      if (earn) all.push(earn);
      all.push(...extractNewsItems(sym, data, 2));
    });

    all.sort((a, b) => (b.ts || 0) - (a.ts || 0));

    setItems(all.slice(0, 30));
    setStatus(all.length === 0 ? 'empty' : 'ready');
  }, []);

  useAC_E(() => {
    let cancelled = false;
    const run = () => { if (!cancelled) load(); };
    run();
    const refresh = setInterval(run, REFRESH_MS);
    const tk = setInterval(() => setTick(x => x + 1), 30000); // re-render time labels
    const onStorage = (e) => {
      if (e.key === WL_KEY_ACT || e.key === ALERTS_KEY_ACT) run();
    };
    window.addEventListener('storage', onStorage);
    return () => {
      cancelled = true;
      clearInterval(refresh);
      clearInterval(tk);
      window.removeEventListener('storage', onStorage);
    };
  }, [load]);

  const now = Date.now();

  return (
    <div className="card activity-card">
      <div className="card-hd">
        <span className="t">Activity</span>
        <span className="explain">Alerts, earnings & news for symbols on your watchlist</span>
        <a className="card-link" href="/bulletin.html">See full view →</a>
      </div>
      <div className="act-legend">
        {Object.entries(KIND_META).map(([k, m]) => (
          <span key={k} className="act-chip"><span className="act-dot" style={{ background: m.dot }} />{m.label}</span>
        ))}
      </div>
      <div className="act-bd">
        {status === 'loading' && (
          <div className="act-empty">Loading watchlist activity…</div>
        )}
        {status === 'empty' && items.length === 0 && (
          <div className="act-empty">
            {readWatchlistSyms().length === 0
              ? <>Your watchlist is empty. <a href="/screener.html">Add symbols</a> to see alerts, earnings, and news here.</>
              : <>No recent alerts, earnings, or news for your watchlist.</>}
          </div>
        )}
        {status === 'error' && (
          <div className="act-empty">Couldn't load activity. Will retry.</div>
        )}
        {items.map(it => {
          const m = KIND_META[it.kind] || KIND_META.news;
          const isExternal = /^https?:/.test(it.href);
          const tLabel = it.kind === 'earn'
            ? (it.meta === 'upcoming' ? 'soon' : '')
            : fmtRelative(it.ts, now);
          return (
            <a key={it.id} className="act-item" href={it.href}
               target={isExternal ? "_blank" : undefined}
               rel={isExternal ? "noreferrer" : undefined}>
              <div className="act-gut" style={{ background: m.dot }} />
              <div className="act-main">
                <div className="act-row1">
                  <span className="act-kind" style={{ color: m.dot }}>{m.label}</span>
                  <span className="act-sym">{it.sym}</span>
                  {tLabel && <span className="act-time tabnum">{tLabel}</span>}
                </div>
                <div className="act-text">{it.text}</div>
                <div className="act-meta">{it.meta}</div>
              </div>
            </a>
          );
        })}
      </div>
    </div>
  );
}

Object.assign(window, { ActivityFeed });
