"""
Polymarket CLOB API — authentication (Phase 1, read-only).

Derives L2 API credentials (key/secret/passphrase) from the L1 wallet private
key via an EIP-712 signed request, then verifies with read-only balance and
position checks. No orders placed here — that's poly_trader.py (Phase 2).

Auth scheme (Polymarket CLOB):
  L1 (wallet-signed): EIP-712 signature over a ClobAuth message, sent to
    GET /auth/derive-api-key to deterministically derive (not create) the
    account's standing API key/secret/passphrase.
  L2 (HMAC): subsequent requests sign `timestamp+method+path+body` with the
    derived secret (HMAC-SHA256, base64url), sent as POLY_SIGNATURE alongside
    POLY_API_KEY / POLY_PASSPHRASE / POLY_ADDRESS / POLY_TIMESTAMP.
"""
import os
import time
import json
import base64
import hmac
import hashlib
from pathlib import Path
from typing import Optional

import requests
from dotenv import load_dotenv
from eth_account import Account
from eth_account.messages import encode_typed_data

load_dotenv(r'E:\soccer\.env')

CLOB_BASE = "https://clob.polymarket.com"
CHAIN_ID = 137  # Polygon mainnet

PRIVATE_KEY = os.getenv("POLY_PRIVATE_KEY")
WALLET_ADDRESS = os.getenv("POLY_WALLET_ADDRESS")

_creds_cache: Optional[dict] = None


def _account():
    if not PRIVATE_KEY:
        raise RuntimeError("POLY_PRIVATE_KEY not set in .env")
    return Account.from_key(PRIVATE_KEY)


def _l1_headers() -> dict:
    """EIP-712 sign a ClobAuth message; returns the L1 auth headers."""
    acct = _account()
    ts = str(int(time.time()))
    nonce = 0
    typed_data = {
        "types": {
            "EIP712Domain": [
                {"name": "name", "type": "string"},
                {"name": "version", "type": "string"},
                {"name": "chainId", "type": "uint256"},
            ],
            "ClobAuth": [
                {"name": "address", "type": "address"},
                {"name": "timestamp", "type": "string"},
                {"name": "nonce", "type": "uint256"},
                {"name": "message", "type": "string"},
            ],
        },
        "primaryType": "ClobAuth",
        "domain": {"name": "ClobAuthDomain", "version": "1", "chainId": CHAIN_ID},
        "message": {
            "address": acct.address,
            "timestamp": ts,
            "nonce": nonce,
            "message": "This message attests that I control the given wallet",
        },
    }
    signable = encode_typed_data(full_message=typed_data)
    signed = acct.sign_message(signable)
    sig = signed.signature.hex()
    if not sig.startswith("0x"):
        sig = "0x" + sig
    return {
        "POLY_ADDRESS": acct.address,
        "POLY_SIGNATURE": sig,
        "POLY_TIMESTAMP": ts,
        "POLY_NONCE": str(nonce),
    }


def derive_api_creds(force: bool = False) -> dict:
    """GET /auth/derive-api-key — L1-signed, returns {apiKey, secret, passphrase}."""
    global _creds_cache
    if _creds_cache is not None and not force:
        return _creds_cache
    headers = _l1_headers()
    r = requests.get(f"{CLOB_BASE}/auth/derive-api-key", headers=headers, timeout=15)
    if r.status_code != 200:
        raise RuntimeError(f"derive-api-key -> {r.status_code}: {r.text}")
    creds = r.json()
    _creds_cache = creds
    return creds


def _l2_headers(method: str, path: str, body: str = "") -> dict:
    creds = derive_api_creds()
    acct_address = WALLET_ADDRESS or _account().address
    ts = str(int(time.time()))
    msg = ts + method.upper() + path + body
    secret_bytes = base64.urlsafe_b64decode(creds["secret"])
    sig = hmac.new(secret_bytes, msg.encode("utf-8"), hashlib.sha256).digest()
    sig_b64 = base64.urlsafe_b64encode(sig).decode("utf-8")
    return {
        "POLY_ADDRESS": acct_address,
        "POLY_API_KEY": creds["apiKey"],
        "POLY_PASSPHRASE": creds["passphrase"],
        "POLY_TIMESTAMP": ts,
        "POLY_SIGNATURE": sig_b64,
    }


def _get(path: str, params: Optional[dict] = None) -> dict:
    headers = _l2_headers("GET", path)
    r = requests.get(CLOB_BASE + path, headers=headers, params=params, timeout=15)
    if r.status_code != 200:
        raise RuntimeError(f"GET {path} -> {r.status_code}: {r.text}")
    return r.json()


def get_balance_allowance() -> dict:
    """GET /balance-allowance — collateral (USDC) balance + exchange allowance."""
    return _get("/balance-allowance", params={"asset_type": "COLLATERAL"})


def get_open_orders() -> dict:
    return _get("/orders")


def get_trades() -> dict:
    return _get("/trades")


if __name__ == "__main__":
    print("=== Phase 1: Polymarket auth check ===")
    print(f"Wallet: {WALLET_ADDRESS}")
    print("\n[1/3] Deriving API credentials (L1 signed request)...")
    creds = derive_api_creds()
    print(f"  OK — apiKey: {creds['apiKey'][:8]}...")

    print("\n[2/3] Checking balance/allowance (L2 signed request)...")
    bal = get_balance_allowance()
    print(f"  {json.dumps(bal, indent=2)}")

    print("\n[3/3] Checking open orders...")
    orders = get_open_orders()
    print(f"  {len(orders) if isinstance(orders, list) else orders} open orders")

    print("\nPhase 1 OK — read-only auth verified. No orders placed.")
