"""
Stake.com API discovery — Firefox, single response handler, extended CF wait.
"""

import json
import time
from datetime import datetime

captured = {
    "graphql_requests": [],
    "rest_requests": [],
    "cookies": [],
    "gql_probe_results": [],
    "performance_entries": [],
}

BORING_EXTS = {".js", ".css", ".png", ".jpg", ".jpeg", ".svg", ".woff",
               ".woff2", ".ico", ".gif", ".webp", ".map", ".ttf", ".otf", ".eot"}
BORING_HOSTS = ["imgix.net", "sanity.io", "cloudflare", "cdn-cgi",
                "challenge-platform", "datadoghq", "datadog", "google-analytics",
                "analytics", "gtm.", "segment.io", "sentry", "hotjar"]

def is_boring(url):
    u = url.lower()
    for h in BORING_HOSTS:
        if h in u:
            return True
    path = u.split("?")[0]
    for ext in BORING_EXTS:
        if path.endswith(ext):
            return True
    return False

def is_api(url):
    u = url.lower()
    if "graphql" in u:
        return True
    kw = ["_api/", "/api/", "/v1/", "/v2/",
          "sport", "event", "market", "odds", "bet",
          "match", "fixture", "league", "prematch", "live/"]
    return any(k in u for k in kw)

current_label = {"v": "?"}

def on_response(response):
    url = response.url
    if is_boring(url):
        return
    if not is_api(url):
        return

    label = current_label["v"]
    method = response.request.method
    status = response.status
    resp_headers = dict(response.headers)
    req_headers = dict(response.request.headers)

    try:
        req_body_raw = response.request.post_data
        req_body = None
        if req_body_raw:
            try:
                req_body = json.loads(req_body_raw)
            except Exception:
                req_body = req_body_raw

        resp_body = None
        ct = resp_headers.get("content-type", "")
        if "json" in ct:
            try:
                resp_body = response.json()
            except Exception:
                pass

        entry = {
            "page": label,
            "url": url,
            "method": method,
            "status": status,
            "request_headers": req_headers,
            "request_body": req_body,
            "response_body": resp_body,
            "ts": datetime.utcnow().isoformat(),
        }

        if "graphql" in url.lower():
            op = None
            if isinstance(req_body, dict):
                op = req_body.get("operationName")
            elif isinstance(req_body, list):
                op = [r.get("operationName") for r in req_body]
            entry["operation_name"] = op
            captured["graphql_requests"].append(entry)
            print(f"  [GQL:{label}] op={str(op)[:60]:60} status={status}")
        else:
            captured["rest_requests"].append(entry)
            print(f"  [REST:{label}] {method} {url[:90]} status={status}")

    except Exception:
        pass

def wait_cf(page, max_s=45):
    """Wait for Cloudflare challenge to clear."""
    start = time.time()
    while time.time() - start < max_s:
        try:
            title = page.title().lower()
            if "just a moment" not in title:
                return True
        except:
            pass
        elapsed = int(time.time() - start)
        print(f"    [CF] {elapsed}s ...")
        time.sleep(4)
    return False

def go(page, url, label, cf_wait=40):
    current_label["v"] = label
    print(f"\n[>> {label}] {url}")
    try:
        page.goto(url, timeout=35000, wait_until="domcontentloaded")
    except Exception as e:
        print(f"  goto warn: {str(e)[:80]}")
    cleared = wait_cf(page, cf_wait)
    print(f"  CF cleared: {cleared}  |  current url: {page.url[:80]}")
    time.sleep(4)
    # lazy-load scroll
    for y in [400, 900, 1600, 2500]:
        try:
            page.evaluate(f"window.scrollTo(0, {y})")
            time.sleep(1)
        except:
            pass
    time.sleep(3)
    return cleared

def probe_graphql(page):
    """Send known Stake.com GraphQL operations from within the page context."""
    queries = [
        # These are real Stake.com operation names seen in the wild
        {
            "operationName": "SportQuery",
            "query": "query SportQuery($slug:String!){sport(slug:$slug){id name slug fixtures(status:UPCOMING,limit:20){id slug name startTime status homeTeam{id name slug}awayTeam{id name slug}markets{id name outcomes{id name odds}}}}}",
            "variables": {"slug": "soccer"}
        },
        {
            "operationName": "SportsQuery",
            "query": "query SportsQuery{sports{id name slug icon fixtures(status:UPCOMING,limit:5){id slug name startTime homeTeam{name}awayTeam{name}}}}",
            "variables": {}
        },
        {
            "operationName": "UpcomingFixtures",
            "query": "query UpcomingFixtures($sport:String!,$limit:Int!){upcomingFixtures(sport:$sport,limit:$limit){id name slug startTime tournament{name}homeTeam{name}awayTeam{name}markets{name outcomes{name price}}}}",
            "variables": {"sport": "soccer", "limit": 10}
        },
        {
            "operationName": "GetSportEvents",
            "query": "query GetSportEvents($sport:String!){getSportEvents(sport:$sport,status:UPCOMING){id slug startTime home away markets{marketName selections{name price}}}}",
            "variables": {"sport": "SOCCER"}
        },
        # Broader probe - introspection (might be blocked)
        {
            "operationName": "IntrospectionQuery",
            "query": "{ __schema { queryType { name } types { name kind } } }",
            "variables": {}
        },
    ]

    results = []
    for q in queries:
        try:
            r = page.evaluate("""
                async (queryObj) => {
                    try {
                        const resp = await fetch('https://stake.com/_api/graphql', {
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                'Accept': 'application/json',
                            },
                            credentials: 'include',
                            body: JSON.stringify(queryObj)
                        });
                        const text = await resp.text();
                        return {
                            status: resp.status,
                            headers: Object.fromEntries(resp.headers.entries()),
                            body: text.slice(0, 4000)
                        };
                    } catch(e) {
                        return { error: e.toString() };
                    }
                }
            """, q)
            status = r.get("status", "?")
            body = r.get("body", "")
            print(f"  probe [{q['operationName']}]: status={status} body_len={len(body)}")
            if body and not body.startswith("<!"):
                print(f"    >> {body[:300]}")
            results.append({"query": q, "result": r})
        except Exception as e:
            print(f"  probe [{q['operationName']}] error: {e}")
            results.append({"query": q, "result": {"error": str(e)}})
    return results

def run():
    from playwright.sync_api import sync_playwright

    with sync_playwright() as p:
        print("[*] Launching Firefox headless=False (Xvfb)")
        browser = p.firefox.launch(headless=False)

        ctx = browser.new_context(
            viewport={"width": 1366, "height": 768},
            user_agent="Mozilla/5.0 (X11; Linux x86_64; rv:122.0) Gecko/20100101 Firefox/122.0",
            locale="en-GB",
            timezone_id="Africa/Lagos",
        )

        page = ctx.new_page()
        page.on("response", on_response)

        # 1. Homepage (builds legit cookies)
        go(page, "https://stake.com/", "home", cf_wait=50)

        # 2. Soccer
        go(page, "https://stake.com/sports/soccer", "soccer", cf_wait=45)

        # Click a match row if possible
        print("  Trying to click a match ...")
        for sel in [
            "a[href*='/sports/soccer/'][href*='/match']",
            "a[href*='/sports/soccer/'][href!='/sports/soccer/']",
            "[class*='EventRow'] a",
            "[class*='event-row'] a",
            "a[href*='/match/']",
        ]:
            try:
                el = page.query_selector(sel)
                if el:
                    href = el.get_attribute("href") or ""
                    print(f"    click {sel} -> {href}")
                    current_label["v"] = "soccer_match"
                    el.click()
                    time.sleep(6)
                    for y in [400, 800]:
                        page.evaluate(f"window.scrollTo(0,{y})")
                        time.sleep(1)
                    break
            except Exception as e:
                print(f"    [warn] {sel}: {e}")

        # 3. Basketball
        go(page, "https://stake.com/sports/basketball", "basketball", cf_wait=30)

        # 4. Tennis
        go(page, "https://stake.com/sports/tennis", "tennis", cf_wait=30)

        # 5. Nigeria URL test
        current_label["v"] = "nigeria"
        print("\n[>> nigeria] checking /ng/ redirect")
        try:
            page.goto("https://stake.com/ng/sports/soccer", timeout=20000,
                      wait_until="domcontentloaded")
            print(f"  Final URL: {page.url}")
        except Exception as e:
            print(f"  warn: {e}")
        time.sleep(4)

        # 6. Direct GraphQL probes
        # Return to soccer to have best session cookies
        go(page, "https://stake.com/sports/soccer", "gql_probe", cf_wait=30)
        print("\n[PHASE: GraphQL direct probe]")
        captured["gql_probe_results"] = probe_graphql(page)

        # 7. Performance API
        try:
            entries = page.evaluate("""
                () => performance.getEntriesByType('resource')
                    .filter(r => r.name.includes('graphql') || r.name.includes('_api'))
                    .map(r => ({name: r.name, type: r.initiatorType, duration: Math.round(r.duration)}))
            """)
            captured["performance_entries"] = entries
            print(f"\n[*] Performance API GQL entries: {len(entries)}")
            for e in entries[:5]:
                print(f"  {e}")
        except Exception as e:
            print(f"  warn perf: {e}")

        captured["cookies"] = ctx.cookies()
        browser.close()

    out = "/home/cyborg/Desktop/claude/arb_bot/tools/stake_discovery_results.json"
    with open(out, "w") as f:
        json.dump(captured, f, indent=2, default=str)

    print(f"\n[DONE] GQL={len(captured['graphql_requests'])} REST={len(captured['rest_requests'])} saved={out}")
    return captured

if __name__ == "__main__":
    data = run()

    print("\n" + "="*70)
    print("INTERCEPTED GQL (unique ops)")
    print("="*70)
    seen = {}
    for r in data["graphql_requests"]:
        op = str(r.get("operation_name", "?"))
        if op not in seen:
            seen[op] = r

    for op, r in sorted(seen.items()):
        print(f"\n  op={op!r}  status={r.get('status')}")
        body = r.get("request_body")
        if isinstance(body, dict):
            q = body.get("query","")
            print(f"  query: {q[:400]}")
            v = body.get("variables",{})
            print(f"  vars:  {v}")
        resp = r.get("response_body")
        if resp:
            print(f"  resp:  {json.dumps(resp)[:1200]}")

    print("\n" + "="*70)
    print("DIRECT GQL PROBE RESULTS")
    print("="*70)
    for pr in data.get("gql_probe_results", []):
        q = pr["query"]
        r = pr["result"]
        print(f"\n  op={q['operationName']!r}")
        print(f"  status={r.get('status')}  error={r.get('error','')}")
        body = r.get("body", "")
        if body and not body.startswith("<!"):
            print(f"  body: {body[:1500]}")

    print("\n" + "="*70)
    print("COOKIES (stake.com domain)")
    print("="*70)
    for c in data.get("cookies", []):
        if "stake" in c.get("domain", "").lower():
            print(f"  name={c['name']!r:30} domain={c['domain']}")
