"""
Navigate directly to the sport-iframe URL (not through surebet247.com).

The iframe at sport-iframe.serhjs.xyz connects to the WS independently.
If we navigate there directly, we bypass the Surebet247 shell and may
get a clean WS session that doesn't compete with the main bots.

Also probes different profiles to find BTTS.

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

import time, collections
import msgpack
from scrapers.surebet247 import _Surebet247Worker, _decode_frame

# Direct iframe URL (brand + key in WS, not needed in iframe URL itself)
IFRAME_URL = ('https://sport-iframe.serhjs.xyz/football'
              '?language=en&currency=ngn&seq=last'
              '&brand=CL38B1&X-Api-Key=b8b92942-ce6a-44e8-a5d5-6bf407e316a2')

CONTEXT   = ['en', 'MOBILE_WEB', 'CL38B1', '', 'NGN']
PROFILES_TO_TRY = [
    'pro_main_period',   # known working — baseline
    'pro_all',
    'pro_extended',
    'pro_popular',
    'pro_full',
    'pro_combo',
    'pro_btts',
    'pro_gg',
    'pro_goals',
]

KNOWN_TYPES = {1: 'Home/Away', 2: '1X2', 4: 'Asian Handicap', 5: 'Over/Under'}


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


def probe_via_iframe(page) -> dict:
    frames_recv = []
    frames_sent = []
    last_recv   = [time.time()]

    def handle_ws(ws):
        if 'direct-feed' not in ws.url:
            return
        print(f'  WS connected: {ws.url[:80]}')
        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)

    print(f'  Navigating directly to iframe URL...')
    page.goto(IFRAME_URL, wait_until='domcontentloaded', timeout=60_000)
    time.sleep(10)
    for _ in range(4):
        page.mouse.wheel(0, 700)
        time.sleep(0.6)
    deadline = time.time() + 25
    while time.time() < deadline:
        time.sleep(1)
        if time.time() - last_recv[0] > 3.0 and frames_recv:
            break

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

    if len(frames_recv) < 3:
        print('  Too few frames — connection may still be blocked.')
        return {}

    # Extract event IDs
    method_by_id = {}
    for frame in frames_sent:
        if isinstance(frame, bytes):
            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])

    event_ids = []
    for frame in frames_sent:
        if not isinstance(frame, bytes):
            continue
        d = _decode_frame(frame)
        if not d or not isinstance(d, (list, tuple)) or len(d) < 5:
            continue
        if str(d[3]) == 'GetMainMarketsByProfileAndEventIds':
            ids = d[4][1] if isinstance(d[4], (list, tuple)) and len(d[4]) > 1 else []
            if isinstance(ids, (list, tuple)):
                event_ids.extend(str(i) for i in ids)
    event_ids = list(dict.fromkeys(event_ids))[:6]

    if not event_ids:
        # fallback from rich event replies
        rich_ids = {rid for rid, m in method_by_id.items()
                    if m in ('GetRichEventsByTournamentIdAndStage', 'GetRichEventsByIds')}
        for frame in frames_recv:
            if not isinstance(frame, bytes):
                continue
            d = _decode_frame(frame)
            if not d or not isinstance(d, (list, tuple)) or d[0] != 2 or len(d) < 4:
                continue
            if 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
            for item in (reply[1] or []):
                if isinstance(item, (list, tuple)) and len(item) >= 2:
                    eid = item[1]
                    if isinstance(eid, (int, str)):
                        event_ids.append(str(eid))
        event_ids = list(dict.fromkeys(event_ids))[:6]

    print(f'  Event IDs: {event_ids}')

    # Try to inject frames using prototype.send hook via evaluate
    # We'll try to find the WS in the page's JS context
    ws_info = page.evaluate("""() => {
        // Try common WS storage patterns
        const checks = [
            () => window._dfw ? 'window._dfw rs=' + window._dfw.readyState : null,
            () => window.__ws ? 'window.__ws rs=' + window.__ws.readyState : null,
        ];
        for (const c of checks) {
            try { const r = c(); if (r) return r; } catch(e) {}
        }
        return 'not found in globals';
    }""")
    print(f'  WS in globals: {ws_info}')

    if not event_ids:
        print('  No event IDs — printing all sent method names:')
        for rid, m in sorted(method_by_id.items()):
            print(f'    rid={rid} method={m}')
        return {}

    # Probe using the same approach as we'd use with a working prototype hook
    # Since we don't have the WS in globals, send via page.evaluate with a raw search
    send_ok = page.evaluate("""(eids, ctx) => {
        // Find any open WebSocket connecting to direct-feed
        const results = [];
        // Check if any WS is accessible in the frame
        try {
            const t = window.performance.getEntriesByType('resource')
                .filter(r => r.name.includes('direct-feed'));
            results.push('resource entries: ' + t.length);
        } catch(e) {}
        return results;
    }""", event_ids, CONTEXT)
    print(f'  Resource check: {send_ok}')

    # Print all unique market types from normal frames
    market_types_seen = collections.defaultdict(list)
    market_ids = {rid for rid, m in method_by_id.items()
                  if m == 'GetMainMarketsByProfileAndEventIds'}
    for frame in frames_recv:
        if not isinstance(frame, bytes):
            continue
        d = _decode_frame(frame)
        if not d or not isinstance(d, (list, tuple)) or d[0] != 2 or len(d) < 4:
            continue
        if str(d[2]) not in market_ids:
            continue
        reply = d[3]
        if not isinstance(reply, (list, tuple)) or len(reply) < 2 or not reply[0]:
            continue
        for item in (reply[1] or []):
            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]
            period = item_key[3] if len(item_key) > 3 else None
            mval   = item[2]
            if not isinstance(mval, (list, tuple)) or not mval:
                continue
            for group in (mval[0] or []):
                if not isinstance(group, (list, tuple)) or len(group) < 2:
                    continue
                spec = group[0]
                ocs  = []
                for oc in (group[1] or []):
                    if isinstance(oc, (list, tuple)) and len(oc) >= 2:
                        oc_type = oc[0][0] if isinstance(oc[0], (list, tuple)) and oc[0] else '?'
                        price   = round(oc[1] / 100, 2) if isinstance(oc[1], (int, float)) else oc[1]
                        ocs.append((oc_type, price))
                if ocs:
                    market_types_seen[(mtype, period)].append(ocs)

    return {'market_types': dict(market_types_seen), 'event_ids': event_ids}


if __name__ == '__main__':
    print('Navigating directly to sport-iframe to bypass session limits...\n')
    worker = _Surebet247Worker()
    result = worker.call(probe_via_iframe, timeout=150)

    if not result:
        print('\nNo data. WS connections still saturated.')
    else:
        mts = result.get('market_types', {})
        print(f'\n\nMarket types seen from direct iframe ({len(mts)} unique type+period):\n')
        for (mtype, period), samples in sorted(mts.items()):
            s = samples[0]
            oc_ids = [o[0] for o in s]
            prices = [o[1] for o in s]
            known  = KNOWN_TYPES.get(mtype, f'UNKNOWN({mtype})')
            print(f'  type={mtype:<5} period={period}  {known:<20}  oc_ids={oc_ids}  prices={prices}')
