#!/usr/bin/env python3
"""Signed NUMUS request example. Requires: pip install cryptography"""

import base64
import hashlib
import json
import secrets
import time
import urllib.parse
import urllib.request

from cryptography.hazmat.primitives import serialization


BASE_URL = "https://api.numus.online"
PARTNER_ID = "partner-001"
METHOD = "PUT"
PATH = "/api/integration/endpoints"
IDEMPOTENCY_KEY = ""


def canonical_query(raw_query: str) -> str:
    grouped: dict[str, list[str]] = {}
    for name, value in urllib.parse.parse_qsl(raw_query, keep_blank_values=True):
        grouped.setdefault(name, []).append(value)
    ordered = [(name, value) for name in sorted(grouped) for value in grouped[name]]
    return urllib.parse.urlencode(ordered)


with open("numus-private.pem", "rb") as source:
    private_key = serialization.load_pem_private_key(source.read(), password=None)

public_key = private_key.public_key().public_bytes(
    serialization.Encoding.OpenSSH,
    serialization.PublicFormat.OpenSSH,
).decode("ascii")

payload = {
    "callbackUrl": "https://api.merchant.example/webhooks/numus",
    "returnUrl": "https://merchant.example/payment/return",
}
body = json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
timestamp = str(int(time.time()))
nonce = secrets.token_hex(16)
parsed_path = urllib.parse.urlsplit(PATH)
canonical = "\n".join(
    [
        timestamp,
        nonce,
        METHOD,
        parsed_path.path,
        canonical_query(parsed_path.query),
        IDEMPOTENCY_KEY,
        hashlib.sha256(body).hexdigest(),
    ]
).encode("utf-8")
signature = base64.b64encode(private_key.sign(canonical)).decode("ascii")
authorization = json.dumps(
    {
        "partnerID": PARTNER_ID,
        "key": public_key,
        "sign": signature,
        "timestamp": timestamp,
        "nonce": nonce,
    },
    separators=(",", ":"),
)

request = urllib.request.Request(
    BASE_URL + PATH,
    data=body,
    method=METHOD,
    headers={
        "Authorization": authorization,
        "Content-Type": "application/json",
    },
)
with urllib.request.urlopen(request, timeout=15) as response:
    print(response.status, response.read().decode("utf-8"))
