"""
Do Kalshi and Poly find the SAME bets or DIFFERENT ones?  Quantify overlap.

poly_backfill rows carry BOTH kalshi_{side}_mid/ask AND poly_{side}_price, so each
book's [0.05,0.12) multiplicative-de-vig strategy runs on identical fixtures. For
each fixture (game_date,league,home,away) decide whether Kalshi fired a bet, whether
Poly fired, and if both, whether they picked the SAME side.

Buckets:
  Kalshi-only / Poly-only / Both-same-side / Both-different-side / neither
Reports counts AND each bucket's WR/ROIturn, so we see if the UNIQUE bets (the ones
only one book finds) are real edge -> i.e. does running both books add independent n.

Two universes:
  (a) ALL backfill fixtures (Poly covers fewer leagues, so coverage gap shows up)
  (b) SHARED-PRICE fixtures only: both books quoted a price (fair overlap test)
Read-only. Multiplicative de-vig (live default), both-sides dedupe to higher CLV.
"""
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(key=key, gd=gd, league=league, ftr=ftr, pre=[r for _, r in pre]))
    return fx

def fire(fx, book):
    """Return (side, price_for_settlement, won, clv) of the book's bet, or None.
       book='kalshi' (price=ask) or 'poly' (price=mid)."""
    cands = []
    have_price = 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_price = 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((clv, side, px, won)); break
    if not cands: return (None, have_price)
    clv, side, px, won = max(cands, key=lambda t: t[0])
    return (dict(side=side, px=px, won=won, clv=clv), have_price)

def roi(bets):
    n = len(bets)
    if not n: return "(0)"
    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)
    mu = sum(b['px'] for b in bets); var = sum(b['px']*(1-b['px']) for b in bets)
    z = (wins-mu)/math.sqrt(var) if var > 0 else 0.0
    return f"n={n:3d} WR={wins/n*100:4.1f}% ROIturn={net/n*100:+6.1f}% z={z:+.2f}"

def main():
    fx = load()
    rows = []
    for f in fx:
        k, k_has = fire(f, 'kalshi')
        p, p_has = fire(f, 'poly')
        rows.append(dict(f=f, k=k, p=p, k_has=k_has, p_has=p_has))

    def report(universe, label):
        K = [r for r in universe if r['k']]
        P = [r for r in universe if r['p']]
        both = [r for r in universe if r['k'] and r['p']]
        konly = [r for r in universe if r['k'] and not r['p']]
        ponly = [r for r in universe if r['p'] and not r['k']]
        same = [r for r in both if r['k']['side'] == r['p']['side']]
        diff = [r for r in both if r['k']['side'] != r['p']['side']]
        union = [r for r in universe if r['k'] or r['p']]
        print(f"\n=== {label} (fixtures={len(universe)}) ===")
        print(f"  Kalshi fired:        {len(K):4d}")
        print(f"  Poly fired:          {len(P):4d}")
        print(f"  UNION (either):      {len(union):4d}")
        print(f"  Both fired:          {len(both):4d}   "
              f"({100*len(both)/len(union):.0f}% of union)" if union else "")
        print(f"    - same side:       {len(same):4d}")
        print(f"    - DIFFERENT side:  {len(diff):4d}")
        print(f"  Kalshi-only:         {len(konly):4d}")
        print(f"  Poly-only:           {len(ponly):4d}")
        if K:
            jac = len(both)/len(union) if union else 0
            print(f"  Jaccard overlap (both/union): {jac:.2f}")
            print(f"  Of Kalshi bets, also on Poly: {100*len(both)/len(K):.0f}%")
        if P:
            print(f"  Of Poly bets, also on Kalshi: {100*len(both)/len(P):.0f}%")
        # do the UNIQUE bets carry edge?
        print(f"\n  Performance by bucket:")
        print(f"    Kalshi-only (Kalshi px):  {roi([r['k'] for r in konly])}")
        print(f"    Poly-only   (Poly px):    {roi([r['p'] for r in ponly])}")
        print(f"    Both, Kalshi side==Poly:  K {roi([r['k'] for r in same])}")
        print(f"    Both, same: Poly side:    P {roi([r['p'] for r in same])}")
        if diff:
            print(f"    Both, DIFFERENT side:     K {roi([r['k'] for r in diff])}")
            print(f"                              P {roi([r['p'] for r in diff])}")

    report(rows, "(a) ALL backfill fixtures")
    shared = [r for r in rows if r['k_has'] and r['p_has']]
    report(shared, "(b) SHARED-PRICE fixtures (both books quoted)")

if __name__ == '__main__':
    main()
