#!/usr/bin/env python3
"""Quote and build a swap on Vurto. Standard library only, no packages."""
import json
import os
import urllib.error
import urllib.request

# Same variable names the CLI reads, so one export serves both.
BASE = os.environ.get("VURTO_SWAP_BASE_URL", "https://swap.vurto.cc")
KEY = os.environ.get("VURTO_SWAP_API_KEY")        # optional: raises your rate limit
WALLET = os.environ.get("VURTO_SWAP_WALLET")      # the address that will sign

CHAIN, TOKEN_IN, TOKEN_OUT, AMOUNT = 42161, "USDC", "WETH", "100"


def call(path, body):
    # Send a User-Agent. The default "Python-urllib/3.x" is refused by the
    # edge with HTTP 403 and "error code: 1010"; any name of your own works.
    headers = {"content-type": "application/json", "user-agent": "vurto-example/1.0"}
    if KEY:
        headers["authorization"] = f"Bearer {KEY}"
    request = urllib.request.Request(
        f"{BASE}{path}", data=json.dumps(body).encode(), headers=headers
    )
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            return json.load(response)
    except urllib.error.HTTPError as error:
        # Errors are JSON too: {"error":{"code":...,"message":...}}. The code is
        # the part worth branching on; the message is for humans.
        detail = json.load(error)
        raise SystemExit(f"{path} failed: {json.dumps(detail)}") from None


quote = call("/v1/quote", {
    "chainId": CHAIN, "tokenIn": TOKEN_IN, "tokenOut": TOKEN_OUT, "amount": AMOUNT,
})

for option in quote["quotes"]:
    print(f"{option['providerLabel']:<14} {option['amountOut']:>26}  {option['id']}")

if not WALLET:
    raise SystemExit("\nSet VURTO_SWAP_WALLET to build a transaction.")

plan = call("/v1/swap", {
    "chainId": CHAIN, "wallet": WALLET, "tokenIn": TOKEN_IN, "tokenOut": TOKEN_OUT,
    "amount": AMOUNT, "maxSlippageBps": 100,
})

chosen = plan["quote"]
route = " > ".join(hop.get("exchange", "") for hop in chosen.get("route", []))
print(f"\nchosen: {chosen['providerLabel']} ({route})")
print(f"out:    {chosen['amountOut']}")
# minimumAmountOut is what the router checks, BEFORE the platform fee is taken.
# What lands in the wallet is that number minus the fee, so do not read it as
# the amount you receive.
print(f"min:    {chosen['minimumAmountOut']} (gross, checked on-chain)")
print(f"steps:  {' -> '.join(step['type'] for step in plan['steps'])}")
print("\nSign each step with the wallet that owns the address above. The bytes are")
print("worthless until it does: no key ever reaches this script or the API.")
