"""
Is the unique-vs-overlap edge a LEAGUE-MIX artifact (like the earlier Poly-vs-Kalshi
headline was)?  Both buckets live ONLY on shared-price fixtures (both books quoted),
so they're already inside the Poly-covered universe. But do UNIQUE bets come from
DIFFERENT leagues than OVERLAP bets?  If unique is concentrated in a few leagues, the
+62% could be those leagues, not cross-book disagreement.

Test: per league, count unique vs overlap bets and each bucket's ROI. The signal is
REAL (not league-mix) only if unique beats overlap WITHIN the same leagues -- i.e. the
two buckets co-occur in the same leagues and unique still wins there.
Multiplicative de-vig, [0.05,0.12), Kalshi@ask / Poly@mid. Read-only.
"""
import csv, glob, os, math
from datetime import datetime
from collections import defaultdict

DIR = r"E:\soccer\poly_backfill"
BAND = (0.05, 0.12)
_FMTS = ['%Y-%m-%d %H:%M:%S', '%m/%d/%Y %H:%M', '%m/%d/%Y %H:%M:%S', '%Y-%m-%d %H:%M']
def _pts(s):
    for f in _FMTS:
        try: return datetime.strptime(s, f)
        except (ValueError, TypeError): pass
    return None
def _f(x):
    try: return float(x)
    except (TypeError, ValueError): return None
def _result(rows):
    for r in reversed(rows):
        v = (r.get('ftr') or '').upper().strip()
        if v in ('H', 'D', 'A'): return v
    return None
def fair_mult(o):
    r = [1.0/x for x in o]; s = sum(r); return [ri/s for ri in r]

def load():
    fixtures = defaultdict(list)
    for path in glob.glob(os.path.join(DIR, "*_polybackfill.csv")):
        with open(path, newline='', encoding='utf-8') as fh:
            for r in csv.DictReader(fh):
                fixtures[(r.get('game_date'), r.get('league'),
                          r.get('home'), r.get('away'))].append(r)
    fx = []
    for key, rows in fixtures.items():
        gd, league, home, away = key
        if not gd: continue
        pre = sorted([(_pts(r['timestamp']), r) for r in rows
                      if (r.get('status') or '').upper() == 'PRE' and _pts(r['timestamp'])],
                     key=lambda t: t[0])
        if not pre: continue
        ftr = _result(rows)
        if ftr is None: continue
        fx.append(dict(gd=gd, league=league, ftr=ftr, pre=[r for _, r in pre]))
    return fx

def fire(fx, book):
    cands = []; have = False
    for side, sidx in (('home', 0), ('away', 2)):
        for r in fx['pre']:
            ph, pd_, pa = _f(r.get('pin_home')), _f(r.get('pin_draw')), _f(r.get('pin_away'))
            if None in (ph, pd_, pa) or not (ph > 1 and pd_ > 1 and pa > 1): continue
            if book == 'kalshi':
                mid = _f(r.get(f'kalshi_{side}_mid')); px = _f(r.get(f'kalshi_{side}_ask'))
            else:
                mid = _f(r.get(f'poly_{side}_price')); px = mid
            if mid is None or px is None or not (0 < mid < 1) or not (0 < px < 1): continue
            have = True
            pf = fair_mult((ph, pd_, pa))[sidx]
            clv = (pf - mid) / pf if pf else None
            if clv is None or not (BAND[0] <= clv < BAND[1]): continue
            won = (fx['ftr'] == 'H' and side == 'home') or (fx['ftr'] == 'A' and side == 'away')
            cands.append(dict(clv=clv, px=px, won=won)); break
    if not cands: return (None, have)
    return (max(cands, key=lambda d: d['clv']), have)

def roi(bets):
    n = len(bets)
    if not n: return None
    wins = sum(b['won'] for b in bets)
    net = sum(((1-b['px'])/b['px']) if b['won'] else -1.0 for b in bets)
    return dict(n=n, wr=wins/n*100, roi=net/n*100)

def main():
    fx = load()
    uniq_by = defaultdict(list); over_by = defaultdict(list)
    for f in fx:
        k, kh = fire(f, 'kalshi'); p, ph = fire(f, 'poly')
        if not (kh and ph): continue
        if k and p:           over_by[f['league']].append(k)
        elif k and not p:     uniq_by[f['league']].append(k)
        elif p and not k:     uniq_by[f['league']].append(p)

    leagues = sorted(set(uniq_by) | set(over_by))
    print(f"shared-price leagues: {len(leagues)}  -> {leagues}\n")
    print("Per league: UNIQUE vs OVERLAP bets (do they co-occur? does unique win within-league?)")
    print(f"  {'lg':6s} | {'uN':>3} {'uWR%':>5} {'uROI%':>7} | {'oN':>3} {'oWR%':>5} {'oROI%':>7} | {'both?':>5}")
    u_tot = o_tot = 0; both_lg = 0
    for lg in leagues:
        u = roi(uniq_by.get(lg, [])); o = roi(over_by.get(lg, []))
        un = u['n'] if u else 0; on = o['n'] if o else 0
        u_tot += un; o_tot += on
        co = 'YES' if (un and on) else ''
        if un and on: both_lg += 1
        uw = f"{u['wr']:5.1f}" if u else "    -"; ur = f"{u['roi']:+7.1f}" if u else "      -"
        ow = f"{o['wr']:5.1f}" if o else "    -"; orr = f"{o['roi']:+7.1f}" if o else "      -"
        print(f"  {lg:6s} | {un:3d} {uw} {ur} | {on:3d} {ow} {orr} | {co:>5}")

    print(f"\n  totals: unique={u_tot}  overlap={o_tot}")
    print(f"  leagues with BOTH unique AND overlap bets: {both_lg}/{len(leagues)}")

    # within-league head-to-head: restrict to leagues having >=5 of EACH, pool, compare
    co_lgs = [lg for lg in leagues if len(uniq_by.get(lg, [])) >= 5 and len(over_by.get(lg, [])) >= 5]
    pu = [b for lg in co_lgs for b in uniq_by[lg]]
    po = [b for lg in co_lgs for b in over_by[lg]]
    print(f"\n  WITHIN-LEAGUE pooled over leagues with >=5 of each ({co_lgs}):")
    su, so = roi(pu), roi(po)
    if su: print(f"    UNIQUE   n={su['n']:3d}  WR={su['wr']:4.1f}%  ROIturn={su['roi']:+6.1f}%")
    if so: print(f"    OVERLAP  n={so['n']:3d}  WR={so['wr']:4.1f}%  ROIturn={so['roi']:+6.1f}%")
    print("  (unique still >> overlap here => NOT a league-mix artifact; same leagues, unique wins)")

if __name__ == '__main__':
    main()
