"""Repair bet_history.json: one bet per signal, not one per venue.

THE BUG. xlow names ONE book as cheap and bets that book. But live_monitor
records `poly_stake` (the signal's named venue) and then, because
Polymarket.com is not tradeable from the US, ALSO writes `kalshi_stake` as a
fallback execution (live_monitor.py ~line 524). daily_signals.resolve_bets then
books P&L on each field independently:

    if bet.get('kalshi_stake') ... kalshi_pnl = ...
    if bet.get('poly_stake')   ... poly_pnl   = ...

so the SAME signal is paid out twice, at two slightly different prices. That is
what produced nightly-email rows like "+100.12 (K:+63.31 P:+36.81)".

Scope: 41 bets are dual-staked; 39 of them are pure paper (no order id at all),
2 have a real Kalshi order. Across those 41, the email reported -$343.47 when a
single bet would be roughly half.

THE REPAIR. Keep exactly ONE venue per bet: the CHEAPER ask, which is what xlow
actually calls and what research/forward_test_unique_book.py already does (that
is why the forward test at n=166 / -5.2% is NOT affected by this bug and needs
no correction). Ties go to Kalshi, which is the executable venue.

Nothing is deleted. The dropped venue's fields are preserved under a `dropped_`
prefix so the original record is fully recoverable and the decision auditable.

Bankrolls are then recomputed from scratch (all three start at $1,000, per
daily_signals.load_*_bankroll defaults) by replaying every resolved bet in date
order, so `*_bankroll_after` and the bankroll json files agree with the repaired
ledger. This matters beyond bookkeeping: _load_kalshi_bankroll feeds Kelly
sizing, so a wrong bankroll silently mis-sizes future bets.

Usage:  python research\\fix_dual_stake_ledger.py [--apply]
        (default is a DRY RUN that reports and changes nothing)
"""
import json
import shutil
import sys
from datetime import datetime

HIST = r'E:\soccer\data\bet_history.json'
BANKROLLS = {
    'b365': r'E:\soccer\data\bankroll.json',
    'kalshi': r'E:\soccer\data\kalshi_bankroll.json',
    'poly': r'E:\soccer\data\poly_bankroll.json',
}
START = 1000.0


def _f(x):
    try:
        return float(x)
    except (TypeError, ValueError):
        return None


def pick_venue(bet):
    """Which single venue should this bet be booked on? Returns 'kalshi'|'poly'.

    The cheaper ASK is the book xlow named, matching fire_xlow's own choice.
    Ties -> kalshi, because Polymarket.com cannot actually be traded from the US
    so it is the wrong venue to attribute a fill to when the price is identical.
    """
    ka, pa = _f(bet.get('kalshi_ask')), _f(bet.get('poly_ask'))
    if ka is None:
        return 'poly'
    if pa is None:
        return 'kalshi'
    return 'poly' if pa < ka - 1e-9 else 'kalshi'


def main():
    apply = '--apply' in sys.argv
    hist = json.load(open(HIST, encoding='utf-8'))
    rows = hist if isinstance(hist, list) else hist.get('bets', hist)

    dual = [r for r in rows if r.get('kalshi_stake') and r.get('poly_stake')]
    print(f'{len(rows)} bets total; {len(dual)} dual-staked\n')

    kept = {'kalshi': 0, 'poly': 0}
    for bet in dual:
        keep = pick_venue(bet)
        drop = 'poly' if keep == 'kalshi' else 'kalshi'
        kept[keep] += 1
        for f in ('stake', 'ask', 'pnl', 'bankroll_after'):
            src = f'{drop}_{f}'
            if src in bet:
                bet[f'dropped_{src}'] = bet.pop(src)
        bet['booked_venue'] = keep
        bet['ledger_repaired'] = '2026-08-01'

    print(f'kept kalshi leg: {kept["kalshi"]}   kept poly leg: {kept["poly"]}\n')

    # ── replay every resolved bet in date order to rebuild bankrolls ──
    order = sorted(rows, key=lambda r: (str(r.get('resolved_at') or r.get('date') or ''),
                                        str(r.get('date') or '')))
    run = {'b365': START, 'kalshi': START, 'poly': START}
    for r in order:
        if r.get('won') is None:
            continue
        for ven, pf, bf in (('b365', 'pnl', 'bankroll_after'),
                            ('kalshi', 'kalshi_pnl', 'kalshi_bankroll_after'),
                            ('poly', 'poly_pnl', 'poly_bankroll_after')):
            v = _f(r.get(pf))
            if v is None:
                continue
            run[ven] = round(run[ven] + v, 2)
            r[bf] = run[ven]

    print('recomputed bankrolls (from $1,000 each):')
    for ven in ('b365', 'kalshi', 'poly'):
        cur = json.load(open(BANKROLLS[ven], encoding='utf-8'))['bankroll']
        print(f'   {ven:7s} {cur:>10,.2f}  ->  {run[ven]:>10,.2f}   '
              f'({run[ven] - cur:+,.2f})')

    if not apply:
        print('\nDRY RUN -- nothing written. Re-run with --apply to commit.')
        return 0

    stamp = datetime.now().strftime('%Y%m%d_%H%M%S')
    shutil.copy2(HIST, f'{HIST}.bak_{stamp}')
    for ven, path in BANKROLLS.items():
        shutil.copy2(path, f'{path}.bak_{stamp}')
    print(f'\nbackups written with suffix .bak_{stamp}')

    json.dump(hist, open(HIST, 'w', encoding='utf-8'), indent=2, ensure_ascii=False)
    for ven, path in BANKROLLS.items():
        json.dump({'bankroll': round(run[ven], 2),
                   'updated': datetime.now().strftime('%Y-%m-%d %H:%M')},
                  open(path, 'w', encoding='utf-8'), indent=2)
    print('bet_history.json and all three bankroll files updated.')
    return 0


if __name__ == '__main__':
    sys.exit(main())
