"""DC Analyst 3 per coin X recipe (v1, 7 Oct 2026). Usage: feats(tok, sym, launch_ts, decision_ts, handle='')"""
import re, sys
sys.path.insert(0, "/opt/common/xsafe"); sys.path.insert(0, "/opt/a3")
import xsafe as xs
RH = re.compile(r"robinhood|\brh\b|hood ?chain|long\.xyz|pons|fomo|stonk|rhchain", re.I)

def query(tok, sym):
    tok = tok.lower()
    if re.match(r'^[A-Za-z][A-Za-z0-9]{1,11}$', sym or ''): return f"({tok} OR ${sym})"
    return tok

def feats(tok, sym, launch_ts, decision_ts, handle='', pages=4):
    tok = tok.lower(); handle = (handle or '').lower().lstrip('@')
    s = xs.search(query(tok, sym), since=launch_ts - 7200, until=decision_ts, pages=pages)
    kept = []
    for t in s['real']:
        a = t.get('author') or {}; au = (a.get('userName') or '').lower(); tx = t.get('text') or ''
        if handle and au == handle: continue
        if tok in tx.lower() or RH.search(tx): kept.append((au, a.get('followers') or 0, xs.ts(t)))
    au = {}
    for a, f, _ in kept: au[a] = max(au.get(a, 0), f)
    first = min((x[2] for x in kept), default=None)
    return dict(auth=len(au), fol=sum(au.values()), big=sum(f >= 10000 for f in au.values()),
                lead_min=(decision_ts - first) / 60 if first else 0, posts=len(kept),
                spam=len(s['spam']), complete=s['complete'], pages=s['n_pages'])
