"""tradeSteward User API: get an access token and list your bots.

Create an API client at https://www.tradesteward.com/useracct/connected-apps, then run:

    TS_CLIENT_ID=... TS_CLIENT_SECRET=... python3 client_credentials.py

Uses only the Python standard library.
"""
import base64
import json
import os
import urllib.error
import urllib.parse
import urllib.request

API = "https://api.tradesteward.com"


def get_token(client_id, client_secret):
    basic = base64.b64encode(
        (urllib.parse.quote(client_id, safe="") + ":" + urllib.parse.quote(client_secret, safe="")).encode()
    ).decode()
    request = urllib.request.Request(
        API + "/oauth/token",
        data=urllib.parse.urlencode({"grant_type": "client_credentials"}).encode(),
        headers={"Authorization": "Basic " + basic, "Content-Type": "application/x-www-form-urlencoded"},
        method="POST",
    )
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            return json.load(response)["access_token"]
    except urllib.error.HTTPError as err:
        raise RuntimeError("token request failed: " + str(err.code))


def get(path, token):
    request = urllib.request.Request(API + "/rest/v1" + path, headers={"Authorization": "Bearer " + token})
    # Every API error is a non-2xx status with the same JSON shape, so read the body of an error too.
    try:
        with urllib.request.urlopen(request, timeout=30) as response:
            body = json.load(response)
    except urllib.error.HTTPError as err:
        body = json.load(err)
    if not body["ok"]:
        raise RuntimeError(body["error"]["code"] + ": " + body["error"]["message"])
    return body["data"]


def main():
    token = get_token(os.environ["TS_CLIENT_ID"], os.environ["TS_CLIENT_SECRET"])
    for bot in get("/bots", token)["bots"]:
        print(bot["botId"], "enabled" if bot["enabled"] else "disabled", bot["botName"])


if __name__ == "__main__":
    main()
