"""
Reconstruct, at SIGNAL-TIME (entry) prices from live_data snapshots:
  (A) Original strategy: YES on the signal side (the team B365 CLV favors).
  (B) NO-opponent: NO on the team we did NOT pick (the favorite).
Both priced at the FIRST PRE snapshot where the B365 CLV signal crossed
threshold (the moment the original bet would have fired) — not closing prices.

Signal definition mirrors daily_signals.scan_fixtures:
  away fires if 0.05 <= clv_b365_away < 0.12
  home fires if 0.05 <= clv_b365_home < 0.12
  if both fire on same snapshot -> keep higher-CLV side.
"""
import csv, glob, math
from collections import defaultdict

EDGE_LO, EDGE_HI = 0.05, 0.12

def f(x):
    try: return float(x)
    except: return None

# group rows by game
games = defaultdict(list)
for fn in sorted(glob.glob('live_data/*.csv')):
    for row in csv.DictReader(open(fn, encoding='utf-8')):
        key = (row['game_date'], row['league'], row['home'], row['away'])
        games[key].append(row)

def in_band(x):
    return x is not None and EDGE_LO <= x < EDGE_HI

def find_entry(rows):
    """Return (side, entry_row) for first PRE snapshot where signal fires, else None.
    Fires on EITHER B365 or Kalshi CLV in [0.05,0.12). Dedupe both-sides to higher CLV
    (max of the two books, matching live_monitor)."""
    rows = [r for r in rows if r['status'] == 'PRE']
    rows.sort(key=lambda r: r['timestamp'])
    for r in rows:
        ba = f(r['clv_b365_away']); ka = f(r['clv_kalshi_away'])
        bh = f(r['clv_b365_home']); kh = f(r['clv_kalshi_home'])
        fires = []
        if in_band(ba) or in_band(ka):
            fires.append(('Away', max(ka or -9, ba or -9)))
        if in_band(bh) or in_band(kh):
            fires.append(('Home', max(kh or -9, bh or -9)))
        if not fires:
            continue
        side = max(fires, key=lambda x: x[1])[0]
        return side, r
    return None

# accumulate bets
orig = []   # (stake, price, won)  YES on signal side
nofav = []  # (stake, price, won)  NO on opponent
skipped_noprice = 0
skipped_nofav_price = 0

for key, rows in games.items():
    res = find_entry(rows)
    if not res:
        continue
    side, r = res
    ftr = r.get('ftr', '')
    if ftr not in ('H', 'D', 'A'):
        continue

    if side == 'Away':
        yes_ask = f(r['kalshi_away_ask'])
        opp_bid = f(r['kalshi_home_bid'])   # opponent = home
        yes_won = (ftr == 'A')
        no_won  = (ftr != 'H')              # NO home wins unless home wins
        p_win   = f(r['pin_fair_away'])
    else:
        yes_ask = f(r['kalshi_home_ask'])
        opp_bid = f(r['kalshi_away_bid'])   # opponent = away
        yes_won = (ftr == 'H')
        no_won  = (ftr != 'A')
        p_win   = f(r['pin_fair_home'])

    # ---- original YES bet at entry ask ----
    if not yes_ask or yes_ask <= 0 or yes_ask >= 0.99:
        skipped_noprice += 1
    else:
        # quarter-kelly stake off $1000 notional, capped $3
        b = (1 - yes_ask) / yes_ask
        kf = max((p_win * b - (1 - p_win)) / b, 0) if p_win else 0
        stake = min(min(0.25 * kf, 0.25) * 1000.0, 3.0)
        if stake >= 1.0:
            orig.append((stake, yes_ask, yes_won))

    # ---- NO on opponent at entry: NO_ask = 1 - opp_bid ----
    if opp_bid is None or opp_bid <= 0:
        skipped_nofav_price += 1
    else:
        no_ask = 1 - opp_bid
        if no_ask <= 0 or no_ask >= 0.99:
            skipped_nofav_price += 1
        else:
            # size NO bet the SAME way (kelly off NO edge vs pin fair of "not opp")
            p_no = 1 - (f(r['pin_fair_home']) if side == 'Away' else f(r['pin_fair_away']))
            bn = (1 - no_ask) / no_ask
            kfn = max((p_no * bn - (1 - p_no)) / bn, 0) if p_no else 0
            stake_n = min(min(0.25 * kfn, 0.25) * 1000.0, 3.0)
            if stake_n >= 1.0:
                nofav.append((stake_n, no_ask, no_won))

def summarize(name, bets):
    n = len(bets)
    wins = sum(1 for s, p, w in bets if w)
    pnl = 0.0; var = 0.0; staked = 0.0
    for s, p, w in bets:
        staked += s
        if w: pnl += s * (1 - p) / p
        else: pnl -= s
        var += s * s * (1 - p) / p
    z = pnl / math.sqrt(var) if var > 0 else 0
    roi = pnl / staked * 100 if staked else 0
    avg_price = sum(p for s, p, w in bets) / n if n else 0
    print(f"\n{name}")
    print(f"  n={n}  WR={wins/n*100:.1f}%  staked=${staked:.0f}")
    print(f"  P&L=${pnl:+.2f}  ROI={roi:+.1f}%  avg entry price={avg_price:.3f}")
    print(f"  Z (ask-as-fair H0) = {z:.2f}")
    return z, pnl, roi

print("="*64)
print(f"Signal games with valid entry snapshot: orig={len(orig)} nofav={len(nofav)}")
print(f"Skipped (no YES price): {skipped_noprice}   (no NO price): {skipped_nofav_price}")
summarize("(A) ORIGINAL — YES on signal side @ entry ask", orig)
summarize("(B) NO-OPPONENT — NO on favorite @ entry (1-bid)", nofav)
