"""BTX HMAC example. Default action: signed GET /v1/account. No order writes."""
import argparse
import hashlib
import hmac
import json
import os
import time
import urllib.error
import urllib.parse
import urllib.request


def encode_query(query=None):
    query = query or {}
    pairs = [(key, value) for key in sorted(query, key=lambda item: item.encode("utf-8"))
             for value in (query[key] if isinstance(query[key], list) else [query[key]])]
    return urllib.parse.urlencode(pairs, quote_via=urllib.parse.quote_plus, safe="~")


def canonical_request(method, escaped_path, timestamp, body=b"", query=None, recv_window="5000", nonce=""):
    if isinstance(body, str):
        body = body.encode("utf-8")
    return "\n".join([method.upper(), escaped_path, encode_query(query),
                      hashlib.sha256(body).hexdigest(), str(timestamp), str(recv_window), nonce])


def sign_request(secret_key, **request):
    return hmac.new(secret_key.encode("utf-8"), canonical_request(**request).encode("utf-8"),
                    hashlib.sha256).hexdigest()


def self_test():
    signature = sign_request("secret", method="POST", escaped_path="/v1/orders", timestamp="1783420800000",
                             body='{"symbol":"BTC-USDT","walletId":21,"side":"buy","type":"limit","timeInForce":"GTC","quantity":"0.100000000","price":"65000.000000000"}')
    if signature != "ec5dcede7caa7214fca3f4f632cea4219a9b5c5e053ea088169bb0bed8e846e0":
        raise RuntimeError("Signing vector failed")
    if encode_query({"slash": "A/B", "note": "space value", "dup": ["z", "a"]}) != "dup=z&dup=a&note=space+value&slash=A%2FB":
        raise RuntimeError("Query vector failed")
    print("BTX signing self-test passed")


class NoRedirect(urllib.request.HTTPRedirectHandler):
    def redirect_request(self, req, fp, code, msg, headers, newurl):
        return None


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--self-test", action="store_true")
    parser.add_argument("--base-url", default="https://api.btxpro.co.kr")
    args = parser.parse_args()
    if args.self_test:
        return self_test()
    api_key, secret_key = os.environ.get("BTX_API_KEY"), os.environ.get("BTX_SECRET_KEY")
    if not api_key or not secret_key:
        raise RuntimeError("Load BTX_API_KEY and BTX_SECRET_KEY from your secret manager first")
    base = urllib.parse.urlsplit(args.base_url)
    if base.scheme not in ("http", "https") or not base.netloc or base.username or base.password or base.query or base.fragment:
        raise RuntimeError("Invalid base URL")
    escaped_path = base.path.rstrip("/") + "/v1/account"
    timestamp = str(time.time_ns() // 1_000_000)
    signature = sign_request(secret_key, method="GET", escaped_path=escaped_path, timestamp=timestamp)
    request = urllib.request.Request(urllib.parse.urlunsplit((base.scheme, base.netloc, escaped_path, "", "")),
                                     headers={"BTX-API-KEY": api_key, "BTX-TIMESTAMP": timestamp,
                                              "BTX-RECV-WINDOW": "5000", "BTX-SIGNATURE": signature})
    try:
        with urllib.request.build_opener(NoRedirect()).open(request, timeout=15) as response:
            print(json.dumps(json.load(response), ensure_ascii=False, indent=2))
    except urllib.error.HTTPError as error:
        payload = json.load(error)
        raise RuntimeError(f"HTTP {error.code}: {payload.get('error', {}).get('code', 'API_ERROR')}; requestId={payload.get('requestId', '')}") from None


if __name__ == "__main__":
    try:
        main()
    except Exception as error:
        raise SystemExit(str(error))
