"""
Get event IDs from the Surebet247 WS RichEvents reply,
then probe different market profiles via direct WS.

Usage:
    python3 tools/discover_surebet247_dc3.py
"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))

import time, threading
import msgpack
import websocket
from scrapers.surebet247 import _Surebet247Worker, _decode_frame

BASE_SITE = 'https://www.surebet247.com'
WS_URL    = ('wss://sport-iframe.serhjs.xyz/direct-feed/feed'
             '?brand=CL38B1&X-Api-Key=b8b92942-ce6a-44e8-a5d5-6bf407e316a2')

CONTEXT = ['en', 'MOBILE_WEB', 'CL38B1', '', 'NGN']

PROFILES_TO_TRY = [
    'pro_main_period',
    'pro_all',
    'pro_dc',
    'pro_combo',
    'pro_extended',
    'pro_popular',
    'pro_default',
    'pro_full',
    'pro_main',
    'pro_1x2_dc',
    'pro_gg',
]


def encode_rpc(req_id, method, args):
    raw = msgpack.packb([4, {}, req_id, method, args], use_bin_type=True)
    return b'\x00' + raw


def capture_event_ids(page) -> list:
    """Navigate to football page and grab event IDs from RichEvents replies."""
    frames_recv = []
    frames_sent = []
    last_recv   = [time.time()]

    def handle_ws(ws):
        if 'direct-feed' not in ws.url:
            return
        ws.on('framereceived', lambda p: (frames_recv.append(p), last_recv.__setitem__(0, time.time())) if isinstance(p, bytes) else None)
        ws.on('framesent',     lambda p: frames_sent.append(p) if isinstance(p, bytes) else None)

    page.on('websocket', handle_ws)
    page.goto(f'{BASE_SITE}/sport/football', wait_until='domcontentloaded', timeout=60_000)
    time.sleep(8)
    for _ in range(6):
        page.mouse.wheel(0, 700)
        time.sleep(0.6)
    deadline = time.time() + 20
    while time.time() < deadline:
        time.sleep(1)
        if time.time() - last_recv[0] > 3.0 and frames_recv:
            break
    try:
        page.remove_listener('websocket', handle_ws)
    except Exception:
        pass

    print(f'  Captured {len(frames_recv)} recv / {len(frames_sent)} sent frames')

    # Build method map from sent frames
    method_by_id = {}
    for frame in frames_sent:
        d = _decode_frame(frame)
        if d and isinstance(d, (list, tuple)) and len(d) >= 4 and d[0] == 4:
            method_by_id[str(d[2])] = str(d[3])

    rich_ids = {rid for rid, m in method_by_id.items()
                if m in ('GetRichEventsByTournamentIdAndStage', 'GetRichEventsByIds')}

    event_ids = []
    for frame in frames_recv:
        d = _decode_frame(frame)
        if not d or not isinstance(d, (list, tuple)) or d[0] != 2:
            continue
        if len(d) < 4 or str(d[2]) not in rich_ids:
            continue
        reply = d[3]
        if not isinstance(reply, (list, tuple)) or len(reply) < 2 or not reply[0]:
            continue
        items = reply[1]
        if not isinstance(items, (list, tuple)):
            continue
        for item in items:
            if isinstance(item, (list, tuple)) and len(item) >= 2:
                eid = item[1]
                if isinstance(eid, (int, str)):
                    event_ids.append(str(eid))

    return list(dict.fromkeys(event_ids))[:8]


def decode_market_reply(data: bytes):
    d = _decode_frame(data)
    if not d or not isinstance(d, (list, tuple)) or d[0] != 2 or len(d) < 4:
        return None, {}
    reply = d[3]
    if not isinstance(reply, (list, tuple)) or len(reply) < 2 or not reply[0]:
        return d[2], {}
    items = reply[1]
    if not isinstance(items, (list, tuple)):
        return d[2], {}

    result = {}
    for item in items:
        if not isinstance(item, (list, tuple)) or len(item) < 3:
            continue
        item_key = item[1]
        if not isinstance(item_key, (list, tuple)) or len(item_key) < 3:
            continue
        mtype = item_key[2]
        mv    = item[2]
        if not isinstance(mv, (list, tuple)) or not mv:
            continue
        sgs = mv[0]
        if not isinstance(sgs, (list, tuple)):
            continue
        for g in sgs:
            if not isinstance(g, (list, tuple)) or len(g) < 2:
                continue
            oc_types, prices = [], []
            for oc in (g[1] or []):
                if isinstance(oc, (list, tuple)) and len(oc) >= 2:
                    k = oc[0]
                    if isinstance(k, (list, tuple)) and k:
                        oc_types.append(k[0])
                    prices.append(round(oc[1] / 100, 2) if isinstance(oc[1], (int, float)) else oc[1])
            if oc_types and mtype not in result:
                result[mtype] = (oc_types, prices)
    return d[2], result


if __name__ == '__main__':
    print('Step 1: Capturing event IDs via browser...')
    pw = _Surebet247Worker()
    event_ids = pw.call(capture_event_ids, timeout=120)
    print(f'  Got {len(event_ids)} event IDs: {event_ids}')

    if not event_ids:
        print('No event IDs. Exiting.')
        sys.exit(1)

    print('\nStep 2: Probing profiles via direct WS...\n')

    replies  = {}
    lock     = threading.Lock()
    ready    = threading.Event()
    pending  = {}
    req_id   = [200]

    def on_open(ws):
        ready.set()

    def on_message(ws, data):
        if not isinstance(data, bytes):
            return
        rid, mkt = decode_market_reply(data)
        if rid is not None and rid in pending:
            with lock:
                replies[rid] = mkt

    def on_error(ws, e):
        print(f'  WS error: {e}')

    ws = websocket.WebSocketApp(WS_URL, on_open=on_open,
                                on_message=on_message, on_error=on_error)
    threading.Thread(target=ws.run_forever, daemon=True).start()

    if not ready.wait(15):
        print('WS timed out'); sys.exit(1)
    print('Connected.\n')

    for profile in PROFILES_TO_TRY:
        rid = req_id[0]; req_id[0] += 1
        pending[rid] = profile
        frame = encode_rpc(rid, 'GetMainMarketsByProfileAndEventIds',
                           [profile, event_ids, 4, 1, CONTEXT])
        ws.send(frame, opcode=websocket.ABNF.OPCODE_BINARY)
        time.sleep(0.4)

    time.sleep(5)
    ws.close()

    for rid, profile in sorted(pending.items()):
        mkt = replies.get(rid)
        if mkt is None:
            print(f'  {profile!r:25s} → no reply')
        elif not mkt:
            print(f'  {profile!r:25s} → empty/error')
        else:
            print(f'  {profile!r:25s} → types: {sorted(mkt.keys())}')
            for mtype in sorted(mkt.keys()):
                oc_types, prices = mkt[mtype]
                print(f'    type={mtype:<5} outcomes={oc_types}  prices={prices}')
