"""AgentPad function for Virtuals G.A.M.E (game-python SDK): `agentpad_buy`.

Buys an AgentPad token (default APBUILD) on its Base bonding curve from your agent's wallet:
ERC-8004 identity (if missing) -> AgentPad agent pass (if missing) -> buy. About $0.01 of Base gas in total.

Env: AGENT_WALLET_PRIVATE_KEY (your agent's Base wallet key; read locally, never logged or sent anywhere),
     BASE_RPC_URL (optional, default https://mainnet.base.org), AGENTPAD_MAX_ETH (optional cap per buy, default 0.05).
pip install game_sdk web3 requests
Curve tokens are tiny, illiquid and can go to zero. No profit is promised.
"""
import os
import requests
from web3 import Web3
from game_sdk.game.custom_types import Argument, Function, FunctionResultStatus

API = os.getenv("AGENTPAD_API", "https://api.agentpadbase.com")
REG = "0x8004a169fb4a3325136eb29fa0ceb6d2e539a432"
TRANSFER = "0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef"


def _plan(wallet, token, eth, agent_id=None):
    params = {"wallet": wallet, "buy": token, "eth": eth}
    if agent_id:
        params["agentId"] = str(agent_id)
    r = requests.get(f"{API}/v1/onboard", params=params, timeout=60).json()
    if not r.get("ok"):
        raise RuntimeError("AgentPad: " + str(r.get("error")))
    return r


def agentpad_buy(token: str = "APBUILD", eth: str = "0.01", agent_id: str = "", **kwargs):
    """Executable for the G.A.M.E Function below. Returns (status, message, info)."""
    try:
        if float(eth) > float(os.getenv("AGENTPAD_MAX_ETH", "0.05")):
            return FunctionResultStatus.FAILED, f"{eth} ETH is above AGENTPAD_MAX_ETH", {}
        w3 = Web3(Web3.HTTPProvider(os.getenv("BASE_RPC_URL", "https://mainnet.base.org")))
        acct = w3.eth.account.from_key(os.environ["AGENT_WALLET_PRIVATE_KEY"])

        def send(c):
            tx = {"to": Web3.to_checksum_address(c["to"]), "data": c["data"], "value": int(c["value"]), "gas": int(c["gas"]),
                  "chainId": 8453, "nonce": w3.eth.get_transaction_count(acct.address, "pending"),
                  "maxFeePerGas": w3.eth.gas_price * 2, "maxPriorityFeePerGas": w3.to_wei(0.001, "gwei")}
            h = w3.eth.send_raw_transaction(acct.sign_transaction(tx).raw_transaction)
            rc = w3.eth.wait_for_transaction_receipt(h, timeout=180)
            if rc["status"] != 1:
                raise RuntimeError(f"{c['step']} tx reverted: {h.hex()}")
            return rc

        p = _plan(acct.address, token or "APBUILD", eth, agent_id or None)
        if p.get("graduated"):
            return FunctionResultStatus.FAILED, f"{p['token']['symbol']} graduated; trade it on Uniswap: {p['dex']}", {}
        if p.get("enoughEth") is False:
            return FunctionResultStatus.FAILED, p.get("fundingNote", "not enough ETH on Base"), {}
        txs = []
        if p["calls"][0]["step"] == "identity":
            rc = send(p["calls"][0])
            txs.append("identity " + rc["transactionHash"].hex())
            log = next(l for l in rc["logs"] if l["address"].lower() == REG and l["topics"][0].hex().removeprefix("0x") == TRANSFER[2:])
            p = _plan(acct.address, token or "APBUILD", eth, int(log["topics"][3].hex(), 16))
        for c in p["calls"]:
            rc = send(c)
            txs.append(f"{c['step']} {rc['transactionHash'].hex()}")
        msg = f"Bought ~{p['buy']['expectedTokens']} {p['token']['symbol']} on AgentPad for {eth} ETH. Can go to zero."
        return FunctionResultStatus.DONE, msg, {"txs": txs, "token": p["token"]["address"]}
    except Exception as e:  # never include secrets in the message
        return FunctionResultStatus.FAILED, f"AgentPad buy failed: {e}", {}


agentpad_buy_fn = Function(
    fn_name="agentpad_buy",
    fn_description=("Buy an AgentPad token (agent-only launchpad on Base) on its bonding curve. Registers the agent first if "
                    "needed (ERC-8004 identity + AgentPad pass, ~$0.01 gas). Tokens are illiquid and can go to zero."),
    args=[
        Argument(name="token", type="string", description="APBUILD (default), APAD, or a 0x AgentPad token address"),
        Argument(name="eth", type="string", description="ETH to spend, e.g. 0.01"),
        Argument(name="agent_id", type="string", description="optional ERC-8004 agentId the wallet already owns", optional=True),
    ],
    executable=agentpad_buy,
)

# Usage with a G.A.M.E worker:
#   from game_sdk.game.worker import Worker
#   worker = Worker(api_key=os.environ["GAME_API_KEY"], description="Trades on AgentPad",
#                   get_state_fn=lambda fn_result, state: {}, action_space=[agentpad_buy_fn])
#   worker.run("buy 0.01 ETH of APBUILD on AgentPad")
