#!/usr/bin/env python3.12
"""Poller: lê window.__aviatorSignalsBuffer do iframe via CDP e repassa pro backend."""

import json
import os
import ssl
import sys
import time
import urllib.request
import websocket

CDP_HOST = 'http://localhost:9222'
BACKEND = 'https://localhost:8766'
SNIPPET_PATH = os.path.join(os.path.dirname(__file__), 'static', 'snippet.js')

# Desabilita verificação SSL pro backend (cert self-signed)
ssl_ctx = ssl._create_unverified_context()


def post_crash(value):
    try:
        req = urllib.request.Request(
            BACKEND + '/api/events',
            data=json.dumps({'kind': 'crash', 'value': value}).encode(),
            headers={'Content-Type': 'application/json'},
            method='POST',
        )
        urllib.request.urlopen(req, context=ssl_ctx, timeout=2).read()
        return True
    except Exception as e:
        print(f'  post_crash error: {e}')
        return False


def post_heartbeat(connected, msgs):
    try:
        req = urllib.request.Request(
            BACKEND + '/api/events',
            data=json.dumps({'kind': 'heartbeat', 'connected': connected, 'msgsReceived': msgs}).encode(),
            headers={'Content-Type': 'application/json'},
            method='POST',
        )
        urllib.request.urlopen(req, context=ssl_ctx, timeout=2).read()
        return True
    except Exception:
        return False


def find_spribe_target():
    try:
        r = urllib.request.urlopen(CDP_HOST + '/json/list', timeout=3)
        targets = json.loads(r.read())
        for t in targets:
            if 'spribegaming.com' in t.get('url', '') or 'spribe.games' in t.get('url', ''):
                return t
    except Exception:
        return None
    return None


def inject_snippet(ws):
    with open(SNIPPET_PATH) as f:
        code = f.read()
    ws.send(json.dumps({
        'id': 100,
        'method': 'Runtime.evaluate',
        'params': {'expression': code, 'returnByValue': True},
    }))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == 100:
            if msg.get('result', {}).get('result', {}).get('exceptionDetails'):
                print('INJECT ERROR:', msg['result']['exceptionDetails'])
                return False
            return True


def evaluate(ws, expr, call_id):
    ws.send(json.dumps({
        'id': call_id,
        'method': 'Runtime.evaluate',
        'params': {'expression': expr, 'returnByValue': True},
    }))
    while True:
        msg = json.loads(ws.recv())
        if msg.get('id') == call_id:
            return msg.get('result', {}).get('result', {}).get('value')


def main():
    print(f'[poller] aguardando target spribegaming.com...')
    target = None
    for _ in range(120):
        target = find_spribe_target()
        if target:
            break
        time.sleep(1)
        print('.', end='', flush=True)
    if not target:
        print('\n[poller] TIMEOUT — nenhum iframe Spribe ativo. Abra Aviator e clique JOGAR.')
        sys.exit(1)

    print(f'\n[poller] target encontrado: {target["url"][:80]}')
    ws = websocket.create_connection(target['webSocketDebuggerUrl'], timeout=10)
    ws.send(json.dumps({'id': 0, 'method': 'Runtime.enable'}))
    ws.recv()

    # Injeta snippet (idempotente)
    if inject_snippet(ws):
        print('[poller] snippet injetado')
    else:
        print('[poller] snippet ja ativo ou erro')

    crashes_sent = 0
    last_heartbeat = 0
    print('[poller] iniciando poll loop... Ctrl+C pra parar.')

    try:
        while True:
            # Pega buffer e esvazia atomicamente
            poll_script = """
(() => {
  const buf = window.__aviatorSignalsBuffer || [];
  window.__aviatorSignalsBuffer = [];
  const stats = window.__aviatorSignalsStats || {};
  return { crashes: buf, stats: { connected: !!stats.wsConnected, msgs: stats.wsMsgs || 0 } };
})()
"""
            try:
                data = evaluate(ws, poll_script, int(time.time() * 1000) % 100000)
            except websocket._exceptions.WebSocketConnectionClosedException:
                print('[poller] WebSocket fechou — reconnectando...')
                time.sleep(2)
                target = find_spribe_target()
                if not target:
                    print('[poller] iframe sumiu, saindo.')
                    break
                ws = websocket.create_connection(target['webSocketDebuggerUrl'], timeout=10)
                ws.send(json.dumps({'id': 0, 'method': 'Runtime.enable'}))
                ws.recv()
                continue
            except Exception as e:
                print(f'[poller] eval error: {e}')
                time.sleep(2)
                continue

            if not data:
                time.sleep(1)
                continue

            # Envia crashes
            for c in data.get('crashes', []):
                if post_crash(c['value']):
                    crashes_sent += 1
                    print(f'[poller] crash enviado: {c["value"]:.2f}x (total: {crashes_sent})')

            # Heartbeat
            now = time.time()
            stats = data.get('stats', {})
            if now - last_heartbeat > 2:
                post_heartbeat(stats.get('connected', False), stats.get('msgs', 0))
                last_heartbeat = now

            time.sleep(1)
    except KeyboardInterrupt:
        print('\n[poller] encerrado pelo usuário')
    finally:
        ws.close()


if __name__ == '__main__':
    main()
