#!/usr/bin/env python3
"""PROPOSED (not deployed): runner milestone dive for Robinhood Chain.
Fires when a coin first closes an hour at or above $500k or $1M, and scores how far it is likely to go in the next 7 days.
Reads existing data READ-ONLY: /opt/runtrack/runtrack.db (tokens, kline, snaps), the coin's first-30-min wallet tape (hist day DB or RPC),
and twitterapi.io for X authors around the crossing. Writes nothing into existing systems; prints one JSON line per coin.
Numbers below come from the 5 Oct 2026 runner study (886 RH coins that crossed $500k, Jun to Oct 2026)."""
import json, sqlite3, time, urllib.request, urllib.parse

# Base odds from the study: share that reached each level within 7 days after the crossing
BASE = {5e5: dict(x2m=.39, x5m=.18, x20m=.06), 1e6: dict(x2m=.56, x5m=.25, x20m=.08)}
# Strongest single signal: speed (hours from first trade to the crossing). Share reaching 5M / 20M after crossing $1M
SPEED_1M = [(1, .38, .15), (6, .35, .10), (24, .17, .02), (72, .11, .04), (1e9, .16, .03)]
SPEED_500K = [(1, .26, .08), (6, .21, .07), (24, .07, .02), (72, .07, .03), (1e9, .10, .02)]

def kline(db, tok):
    k = db.execute("select t, close, volume from kline where chain='robinhood' and address=? order by t", (tok,)).fetchall()
    s = db.execute("select mc/price from snaps where chain='robinhood' and address=? and price>0 and mc>0 limit 1", (tok,)).fetchone()
    return k, (s[0] if s else None)

def crossing(k, supply, level):
    """first hourly close at or above level; also the straight-up check (low/high of the 24 h before)"""
    mc = [(t, c * supply, v or 0) for t, c, v in k]
    i = next((j for j, x in enumerate(mc) if x[1] >= level), None)
    if i is None: return None
    prev = mc[max(0, i - 24):i + 1]
    return dict(t=mc[i][0], straight_up=min(x[1] for x in prev) / max(x[1] for x in prev) >= .7,
                hours_above_500k_before=sum(1 for x in mc[:i] if x[1] >= 5e5))

def x_authors(key, tok, t0, t1):
    q = '%s since_time:%d until_time:%d' % (tok, t0, t1); a = set(); cur = ''
    for _ in range(3):
        u = 'https://api.twitterapi.io/twitter/tweet/advanced_search?' + urllib.parse.urlencode(dict(query=q, queryType='Latest', cursor=cur))
        d = json.loads(urllib.request.urlopen(urllib.request.Request(u, headers={'X-API-Key': key}), timeout=30).read())
        a |= {(t.get('author') or {}).get('userName') for t in d.get('tweets') or []}
        if not d.get('has_next_page'): break
        cur = d.get('next_cursor') or ''
    a.discard(None); return len(a)

def score(level, age_h, straight_up, x_before, x_after6=None, launch=None):
    """odds of reaching 5M and 20M within 7 days. launch = dict(buyers_60s, runner_vets_5m, top10_30m) from the first 30 min tape"""
    table = SPEED_1M if level >= 1e6 else SPEED_500K
    p5, p20 = next((a, b) for h, a, b in table if age_h < h)
    why = ['crossed %s %.1f h after the first trade' % ('$1M' if level >= 1e6 else '$500k', age_h)]
    if straight_up: p5 *= 1.5; p20 *= 1.9; why.append('straight up, no deep dip in the last 24 h')
    if x_before >= 10: p5 *= .35; p20 *= .6; why.append('already loud on X before the crossing (%d authors): usually a shilled coin' % x_before)
    elif x_before == 0: p5 *= 1.15; p20 *= 1.5; why.append('silent on X before the crossing')
    if x_after6 is not None:   # only usable 6 h after the crossing
        if x_after6 >= 10: p5 *= 1.4; p20 *= 1.5; why.append('X picked it up after the crossing (%d authors in 6 h)' % x_after6)
        elif x_after6 == 0: p5 *= .6; p20 *= .8; why.append('nobody on X after the crossing')
    if launch:
        if launch.get('top10_30m', 0) <= .15: p20 *= 1.3; why.append('wide holder spread at 30 min')
        if launch.get('runner_vets_5m', 0) == 0 and launch.get('buyers_60s', 99) <= 10: p20 *= 1.3; why.append('stealth start (no runner alumni, quiet first minute)')
    p5 = min(p5, .9); p20 = min(p20, p5)
    action = 'STRONG' if p20 >= .15 else 'WATCH' if p5 >= .25 else 'SKIP'
    return dict(p5m=round(p5, 2), p20m=round(p20, 2), action=action, why=why)

if __name__ == '__main__':
    import sys
    tok, level = sys.argv[1].lower(), float(sys.argv[2] if len(sys.argv) > 2 else 1e6)
    db = sqlite3.connect('file:/opt/runtrack/runtrack.db?mode=ro', uri=True)
    k, sup = kline(db, tok); c = crossing(k, sup, level) if k and sup else None
    if not c: print(json.dumps(dict(tok=tok, note='no crossing in kline'))); sys.exit()
    start = k[0][0]   # replace with the true first trade time from the launch tape when available
    key = json.load(open('/opt/x-alert/config.json')).get('twitterapi_key') if False else None   # wire to the existing key store, never print it
    xb = x_authors(key, tok, c['t'] - 86400, c['t']) if key else 0
    print(json.dumps(dict(tok=tok, level=level, crossed_bkk=time.strftime('%d %b %H:%M', time.gmtime(c['t'] + 25200)),
                          **score(level, (c['t'] - start) / 3600, c['straight_up'], xb))))
