#!/usr/bin/env python3
"""Crowd before / during / after (12h) a new-ATH breakout vs how far it runs.
Targets: class (FAIL/SIDEWAYS/SMALL/MEDIUM/BIG, 7d from old ATH) and the leak-free view from T+12h (WIN +50% before LOSS -30%)."""
import json, glob, random, statistics as st, collections, importlib.util
sp = importlib.util.spec_from_file_location("a", "/opt/bostudy/bo_anal_lib.py"); a = importlib.util.module_from_spec(sp); sp.loader.exec_module(a)
EV = {f'{e["address"]}:{e["t"]}': e for e in json.load(open("/opt/bostudy/events.json"))}
O = json.load(open("/opt/bostudy/outcomes2.json"))
def load(pat):
    d = {}
    for fn in glob.glob(pat):
        for l in open(fn):
            try: r = json.loads(l); d[r["k"]] = r
            except Exception: pass
    return d
PRE, AFT = load("/opt/bostudy/xraw_*.jsonl"), load("/opt/bostudy/xraw.jsonl")
PRE.update(AFT); AFT = load("/opt/bostudy/xafter*.jsonl")
def tag(p, e): return a.human(p) and (("$" + (e["symbol"] or "").lower()) in (p.get("text") or "").lower() or e["address"].lower() in (p.get("text") or "").lower()) and a.same(p, e)
rows = []
for k, o in O.items():
    if k not in PRE or k not in AFT: continue
    e = EV[k]; T = e["t"]
    L = [p for p in PRE[k]["last10"]["real"] if tag(p, e)]; B = [p for p in PRE[k]["base"]["real"] if tag(p, e)]
    A = [p for p in AFT[k]["after12"]["real"] if tag(p, e)]
    hA = [sum(1 for p in A if T + h * 3600 <= p["ts"] < T + (h + 1) * 3600) for h in range(12)]
    preauth = {p["user"] for p in L + B}; aauth = {p["user"] for p in A}
    pre_rate = (len(L) + len(B)) / 34 + 0.05
    rows.append(dict(k=k, coin=e["address"], chain=e["chain"], t=T, cls=o["cls"], big=1 if o["cls"] == "BIG" else 0,
        run2=1 if o["cls"] in ("MEDIUM", "BIG") else 0, fail=1 if o["cls"] == "FAIL" else 0,
        win12=1 if o["hit12"] == "WIN" else 0, loss12=1 if o["hit12"] == "LOSS" else 0, g12=o["gain_after12"], p12=o["p12_vs_ath"],
        complete=AFT[k]["after12"]["complete"],
        pre10=len(L), pre_ratio=(len(L) / 10 + 0.05) / (len(B) / 24 + 0.05),
        during3=sum(hA[:3]), during_ratio=(sum(hA[:3]) / 3 + 0.05) / pre_rate,
        after12=len(A), after_ratio=(len(A) / 12 + 0.05) / pre_rate,
        after_trend=(sum(hA[6:]) + 0.5) / (sum(hA[:6]) + 0.5),
        new_auth=len(aauth - preauth), new_auth_share=(len(aauth - preauth) / len(aauth)) if aauth else None,
        big_acc_after=sum(1 for p in A if (p.get("fol") or 0) >= 10000),
        likes_after=(st.mean([p.get("likeCount") or 0 for p in A]) if A else None),
        reply_share_after=(sum(1 for p in A if p.get("isReply")) / len(A)) if A else None))
json.dump(rows, open("/opt/bostudy/rows2.json", "w"))
n = len(rows); print("events", n, "coins", len({r["coin"] for r in rows}), collections.Counter(r["cls"] for r in rows))
print("rates: BIG 3x+ %.0f%%, MEDIUM+BIG 2x+ %.0f%%, FAIL %.0f%% | from T+12h: WIN %.0f%% LOSS %.0f%%" % tuple(100 * st.mean(r[x] for r in rows) for x in ("big", "run2", "fail", "win12", "loss12")))
def boot(H, Lo, y, n=1000):
    coins = list({r["coin"] for r in H + Lo}); by = collections.defaultdict(list)
    for r in H: by[r["coin"]].append((1, r[y]))
    for r in Lo: by[r["coin"]].append((0, r[y]))
    out = []
    for _ in range(n):
        h = l = hn = ln = 0
        for c in random.choices(coins, k=len(coins)):
            for g, v in by[c]:
                if g: h += v; hn += 1
                else: l += v; ln += 1
        if hn and ln: out.append(h / hn - l / ln)
    out.sort(); return out[int(.05 * len(out))], out[int(.95 * len(out))]
random.seed(2); tmid = sorted(r["t"] for r in rows)[n // 2]; pmid = st.median(r["p12"] for r in rows)
F = ["pre10", "pre_ratio", "during3", "during_ratio", "after12", "after_ratio", "after_trend", "new_auth", "new_auth_share", "big_acc_after", "likes_after", "reply_share_after", "p12"]
for y, name in (("big", "BIG runner 3x+"), ("run2", "2x+ runner"), ("fail", "FAIL"), ("win12", "from T+12h WIN (+50% first)"), ("loss12", "from T+12h LOSS (-30% first)")):
    print(f"\n== {name}: top third vs bottom third, pts (90% CI) | early late RH SOL | price-strong half / weak half (p12 split)")
    for f in F:
        v = [r for r in rows if r[f] is not None]
        xs_ = sorted(r[f] for r in v); lo, hi = xs_[len(xs_) // 3], xs_[2 * len(xs_) // 3]
        H = [r for r in v if (r[f] > lo if lo == hi else r[f] >= hi)]; Lo = [r for r in v if r[f] <= lo]
        if len(H) < 20 or len(Lo) < 20: continue
        d = st.mean(r[y] for r in H) - st.mean(r[y] for r in Lo); ci = boot(H, Lo, y)
        def sp(c):
            h = [r[y] for r in H if c(r)]; l = [r[y] for r in Lo if c(r)]
            return f"{(st.mean(h) - st.mean(l)) * 100:+.0f}" if len(h) >= 8 and len(l) >= 8 else "na"
        flag = " <<" if ci[0] > 0 or ci[1] < 0 else ""
        print(f"  {f:18s} {st.mean(r[y] for r in H):4.0%} vs {st.mean(r[y] for r in Lo):4.0%} {d*100:+4.0f} [{ci[0]*100:+.0f},{ci[1]*100:+.0f}] | {sp(lambda r: r['t'] < tmid)} {sp(lambda r: r['t'] >= tmid)} {sp(lambda r: r['chain'] == 'robinhood')} {sp(lambda r: r['chain'] == 'sol')} | {sp(lambda r: r['p12'] >= pmid)} / {sp(lambda r: r['p12'] < pmid)}{flag}")
